django model - queryset issue - python

I am trying to search for an item in db. there are two items in db, but i cannot get the second one somehow. with my code below the result is only the first row of Bewertung but not the second one.
my code is simple:
locations = Location.objects.all()[:5]
bewertungs = Bewertung.objects.filter(von_location__in=locations)
what can be the reason of why i cannot find the second entry in db? i am getting the first record where bewertung is 4, but the second isnot coming up in the result.
EDIT:
this is the Bewertung Model.
class Bewertung(models.Model):
von_location= models.ForeignKey(Location,related_name="locations_bewertung",default="")
von_user = models.ForeignKey(User,related_name="users_bewertung",default="")
price_leistung = models.IntegerField(max_length=5,default=00)
romantic = models.IntegerField(max_length=3,default=00)
bewertung = models.IntegerField(max_length=3,default=00)
def __unicode__(self):
return self.bewertung
these are the records:

class Bewertung(models.Model):
//you don't have to put default="" because this is already required
von_location= models.ForeignKey(Location,related_name="locations_bewertung")
von_user = models.ForeignKey(User,related_name="users_bewertung")
//use DecimalField instead of IntergerField
//use max_digits not max_length because it is for string
price_leistung = models.DecimalField(max_digits=3, decimal_place=2, default=0)
romantic = models.DecimalField(max_digits=3, decimal_place=2, default=0)
bewertung = models.DecimalField(max_digits=3, decimal_place=2, default=0)
//you return your unicode with an int field which result to error
//so you must do it this way
def __unicode__(self):
return "{0}".format(self.bewertung)

Related

Trying to get two random samples to have the same matching foreignkey value

I am working on a django app that creates random fantasy character names that pull from the following models:
class VillagerFirstNames(models.Model):
first_name=models.CharField(max_length=30, unique=True)
race = models.ForeignKey(Race, on_delete=models.CASCADE)
def __str__(self):
return self.first_name
class VillagerLastNames(models.Model):
last_name = models.CharField(max_length=30, unique=True)
race = models.ForeignKey(Race, on_delete=models.CASCADE)
def __str__(self):
return self.last_name
My issue is arising in my Views. In order to pull a random.sample I have to convert my query to a list like so:
foreign_first = list(VillagerFirstNames.objects.all()
foreign_first_random = random.sample(foreign_first, 3)
context["foreign_first"] = foreign_first_random
foreign_last = list(VillagerLastNames.objects.filter(race__race=foreign_first_random.race))
context["foreign_last"] = random.sample(foreign_last, 3)
Basically, I want the last names pulled to be of the same race as the ones pulled in the first random sample. I'm having trouble figuring this one out, since the way I'm doing it above takes away the "race" attribute from foreign_first_random.
You can do random selection in Race, from there you can select random VillagerFirstNames and VillagerLastNames. For example:
race = Race.objects.all().order_by('?').first()
race_firstname = race.villagerfirstname_set.all().order_by('?').first()
race_lastname = race.villagerlastname_set.all().order_by('?').first()
Here order_by('?') makes the queryset random.
Update
To pass the values to template, you can try like this:
context["foreign_first"] = race.villagerfirstname_set.order_by('?')[:5]
context["foreign_last"] = race.villagerlastname_set.order_by('?')[:5]

Django : Best way to Query a M2M Field , and count occurences

class Edge(BaseInfo):
source = models.ForeignKey('Node', on_delete=models.CASCADE,related_name="is_source")
target = models.ForeignKey('Node', on_delete=models.CASCADE,related_name="is_target")
def __str__(self):
return '%s' % (self.label)
class Meta:
unique_together = ('source','target','label','notes')
class Node(BaseInfo):
item_type_list = [('profile','Profile'),
('page','Page'),
('group','Group'),
('post','Post'),
('phone','Phone'),
('website','Website'),
('email','Email'),
('varia','Varia')
]
item_type = models.CharField(max_length=200,choices=item_type_list,blank = True,null=True)
firstname = models.CharField(max_length=200,blank = True, null=True)
lastname = models.CharField(max_length=200,blank = True,null=True)
identified = models.BooleanField(blank=True,null=True,default=False)
username = models.CharField(max_length=200, blank=True, null=True)
uid = models.CharField(max_length=200,blank=True,null=True)
url = models.CharField(max_length=2000,blank=True,null=True)
edges = models.ManyToManyField('self', through='Edge',blank = True)
I have a Model Node (in this case a soc media profile - item_type) that has relations with other nodes (in this case a post). A profile can be the author of a post. An other profile can like or comment that post.
Question : what is the most efficient way to get all the distinct profiles that liked or commented on anothes profile's post + the count of these likes /comments.
print(Edge.objects.filter(Q(label="Liked")|Q(label="Commented"),q).values("source").annotate(c=Count('source')))
Gets me somewhere but i have the values then (id) and i want to pass the objects to my template rather then .get() all the profiles again...
Result :
Thanks in advance
I ended up with iterating over the queryset and adding the objects that i wanted in a dictionary , if the object was already in dictionary , i would count +1 and add the relation in a nested list.
This doesnt feel right but works for now.
posts = Edge.objects.filter(source = self,target__item_type='post',label='Author')
if posts:
q = Q()
for post in posts:
q = q | Q(target=post.target)
contributors = Edge.objects.filter(Q(label="Liked")|Q(label="Commented"),q)
if contributors:
for i in contributors:
if i.source.uid in results:
if i.label in results[i.source.uid]['relation']:
pass
else:
results[i.source.uid]["relation"].append(i.label)
if 'post' in results[i.source.uid]:
results[i.source.uid]['post'].append(i.target)
else:
results[i.source.uid]['post']=[i.target]
else:
results[i.source.uid] = {'profile' : i.source , 'relation':[i.label],'post':[i.target]}

How to update queryset value in django?

I have written a python script in my project. I want to update the value of a field.
Here are my modes
class News_Channel(models.Model):
name = models.TextField(blank=False)
info = models.TextField(blank=False)
image = models.FileField()
website = models.TextField()
total_star = models.PositiveIntegerField(default=0)
total_user = models.IntegerField()
class Meta:
ordering = ["-id"]
def __str__(self):
return self.name
class Count(models.Model):
userId = models.ForeignKey(User, on_delete=models.CASCADE)
channelId = models.ForeignKey(News_Channel, on_delete=models.CASCADE)
rate = models.PositiveIntegerField(default=0)
def __str__(self):
return self.channelId.name
class Meta:
ordering = ["-id"]
This is my python script:
from feed.models import Count, News_Channel
def run():
for i in range(1, 11):
news_channel = Count.objects.filter(channelId=i)
total_rate = 0
for rate in news_channel:
total_rate += rate.rate
print(total_rate)
object = News_Channel.objects.filter(id=i)
print(total_rate)
print("before",object[0].total_star,total_rate)
object[0].total_star = total_rate
print("after", object[0].total_star)
object.update()
After counting the total_rate from the Count table I want to update the total star value in News_Channel table. I am failing to do so and get the data before the update and after the update as zero. Although total_rate has value.
The problem
The reason why this fails is because here object is a QuerySet of News_Channels, yeah that QuerySet might contain exactly one News_Channel, but that is irrelevant.
If you then use object[0] you make a query to the database to fetch the first element and deserialize it into a News_Channel object. Then you set the total_star of that object, but you never save that object. You only call .update() on the entire queryset, resulting in another independent query.
You can fix this with:
objects = News_Channel.objects.filter(id=i)
object = objects[0]
object.total_star = total_rate
object.save()
Or given you do not need any validation, you can boost performance with:
News_Channel.objects.filter(id=i).update(total_star=total_rate)
Updating all News_Channels
If you want to update all News_Channels, you actually better use a Subquery here:
from django.db.models import OuterRef, Sum, Subquery
subq = Subquery(
Count.objects.filter(
channelId=OuterRef('id')
).annotate(
total_rate=Sum('rate')
).order_by('channelId').values('total_rate')[:1]
)
News_Channel.objects.update(total_star=subq)
The reason is that object in your case is a queryset, and after you attempt to update object[0], you don't store the results in the db, and don't refresh the queryset. To get it to work you should pass the field you want to update into the update method.
So, try this:
def run():
for i in range(1, 11):
news_channel = Count.objects.filter(channelId=i)
total_rate = 0
for rate in news_channel:
total_rate += rate.rate
print(total_rate)
object = News_Channel.objects.filter(id=i)
print(total_rate)
print("before",object[0].total_star,total_rate)
object.update(total_star=total_rate)
print("after", object[0].total_star)
News_Channel.total_star can be calculated by using aggregation
news_channel_obj.count_set.aggregate(total_star=Sum('rate'))['total_star']
You can then either use this in your script:
object.total_star = object.count_set.aggregate(total_star=Sum('rate'))['total_star']
Or if you do not need to cache this value because performance is not an issue, you can remove the total_star field and add it as a property on the News_Channel model
#property
def total_star(self):
return self.count_set.aggregate(total_star=Sum('rate'))['total_star']

How do I store a string in ArrayField? (Django and PostgreSQL)

I am unable to store a string in ArrayField. There are no exceptions thrown when I try to save something in it, but the array remains empty.
Here is some code from models.py :
# models.py
from django.db import models
import uuid
from django.contrib.auth.models import User
from django.contrib.postgres.fields import JSONField, ArrayField
# Create your models here.
class UserDetail(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
key = models.CharField(max_length=50, default=False, primary_key=True)
api_secret = models.CharField(max_length=50)
user_categories = ArrayField(models.CharField(max_length = 1000), default = list)
def __str__(self):
return self.key
class PreParentProduct(models.Model):
product_user = models.ForeignKey(UserDetail, default=False, on_delete=models.CASCADE)
product_url = models.URLField(max_length = 1000)
pre_product_title = models.CharField(max_length=600)
pre_product_description = models.CharField(max_length=2000)
pre_product_variants_data = JSONField(blank=True, null=True)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
def __str__(self):
return self.pre_product_title
I try to save it this way:
catlist = ast.literal_eval(res.text)
for jsonitem in catlist:
key = jsonitem.get('name')
id = jsonitem.get("id")
dictionary = {}
dictionary['name'] = key
dictionary['id'] = id
tba = json.dumps(dictionary)
print("It works till here.")
print(type(tba))
usersearch[0].user_categories.append(tba)
print(usersearch[0].user_categories)
usersearch[0].save()
print(usersearch[0].user_categories)
The output I get is:
It works till here.
<class 'str'>
[]
It works till here.
<class 'str'>
[]
[]
Is this the correct way to store a string inside ArrayField?
I cannot store JSONField inside an ArrayField, so I had to convert it to a string.
How do I fix this?
Solution to the append problem.
You haven't demonstrated how your usersearch[0] I suspect it's something like this:
usersearch = UserDetail.objects.all()
If that is so you are making changes to a resultset, those things are immutable. Try this you will see that the id is unchanged too:
usersearch[0].id = 1000
print usersearch.id
But this works
usersearch = list(UserDetail.objects.all())
and so does
u = usersearch[0]
Solution to the real problem
user_categories = ArrayField(models.CharField(max_length = 1000), default = list)
This is wrong. ArrayFields shouldn't be used in this manner. You will soon find that you need to search through them and
Arrays are not sets; searching for specific array elements can be a
sign of database misdesign. Consider using a separate table with a row
for each item that would be an array element. This will be easier to
search, and is likely to scale better for a large number of elements
ref: https://www.postgresql.org/docs/9.5/static/arrays.html
You need to normalize your data. You need to have a category model and your UserDetail should be related to it through a foreign key.

I need to query for a set of objects whose primary keys are contained inside of a list

As the title says, I need a way to perform this query. I have tried the following:
user_list_ids = []
user_lists = []
user_entries = OwnerEntry.objects.filter(name=request.user)
for user in user_entries:
user_list_ids.append(user.list_id)
user_lists = ListEntry.objects.filter(id__in=user_list_ids)
for user in user_entries:
user_list_ids.append(user.list_id)
user_lists = ListEntry.objects.filter(id__in=user_list_ids)
However, I get an error on the last line: int() argument must be a string or a number, not 'ListEntry'
Here are the relevant models:
class OwnerEntry(models.Model):
name = models.CharField(max_length=32)
list_id = models.ForeignKey(ListEntry)
class Meta:
ordering = ('name',)
class ListEntry(models.Model):
name = models.CharField(max_length=64)
# active_date = models.DateTimeField('date of last list activity')
expire_date = models.DateField('date of expiration')
create_date = models.DateField('date created')
to answer your question directly, please note that you have a list_id rather than list as a ForeignKey name (OwnerEntry model). In order to actually extract the fk value, you should use list_id_id instead (or rename list_id to list ;))
Please also note that django supports object references, like so:
someowner = OwnerEntry.objects.get( ... )
ownerslist = someowner.listentry_set.all()
cheers!
You can define OwnerEntry's foreign key to ListEntry as :
list_id = models.ForeignKey(ListEntry, related_query_name='owner_entry')
and then do this one-liner in your code:
user_lists = ListEntry.objects.filter(owner_entry__name=request.user)
What this does is exactly filter every ListEntry which has at least one owner_entry whose name is equal to request.user's.
The redefinition of the foreign key is just for the sake of giving a nice name to the query attribute.
For more details on queries that work with backward relationships: https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships

Categories

Resources