I have two models:
class Item(models.Model):
name = models.CharField()
class Param(models.Model):
product = models.ForeignKey(Item, related_name="param")
height = models.IntegerField()
price = models.IntegerField()
I want is to annotate item with average price, but only keep params with height > 60.
items = Item.objects.filter(param__height__gt=60).annotate(price=Avg('param__price'))
That's where I have problems. I want to fetch filtered Param objects from above query.
Is it possible to do?
I know that there is workaround:
for item in items:
item.params = item.param.filter(height__gt=60)
But there are a lot of additional queries.
So, my question whether can I access filtered param objects from items?
items = Item.objects.select_related('param').filter(param__height__gt=60).annotate(price=Avg('param__price')).all()
class Artist():
blah = models.TextField()
class Album()
blah = models.ForeignKey(blah)
the key is to be shaed in the class like this^
Also for example the key can be x,y points, time, user, or whatever you want!
https://github.com/Ry10p/django-Plugis/blob/master/courses/models.py
example line 52
-Cheers
Related
I'm trying to get all values in current table, and also get some fields in related tables.
class school(models.Model):
school_name = models.CharField(max_length=256)
school_type = models.CharField(max_length=128)
school_address = models.CharField(max_length=256)
class hometown(models.Model):
hometown_name = models.CharField(max_length=32)
class person(models.Model):
person_name = models.CharField(max_length=128)
person_id = models.CharField(max_length=128)
person_school = models.ForeignKey(school, on_delete=models.CASCADE)
person_ht = models.ForeignKey(hometown, on_delete=models.CASCADE)
how to quick select all info i needed into a dict for rendering.
there will be many records in person, i got school_id input, and want to get all person in this school, and also want these person's hometown_name shown.
i tried like this, can get the info i wanted. And any other quick way to do it?
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name'))
person_name, person_id, school_name, school_address, hometown_name
if the person have many fields, it will be a hard work for list all values.
what i mean, is there any queryset can join related tables' fields together, which no need to list fields in values.
Maybe like this:
m=person.objects.filter(person_school_id=1).XXXX.values()
it can show all values in school, and all values in hometown together with person's values in m, and i can
for x in m:
print(x.school_name, x.hometown_name, x.person_name)
You add a prefetch_related query on top of your queryset.
prefetch_data = Prefetch('person_set, hometown_set, school_set', queryset=m)
Where prefetch_data will prepare your DB to fetch related tables and m is your original filtered query (so add this below your Person.objects.filter(... )
Then you do the actual query to the DB:
query = query.prefetch_related(prefetch_data)
Where query will be the actual resulting query with a list of Person objects (so add that line below the prefetch_data one).
Example:
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name'))
prefetch_data = Prefetch('person_set, hometown_set, school_set', queryset=m)
query = query.prefetch_related(prefetch_data)
In that example I've broken down the queries into more manageable pieces, but you can do the whole thing in one big line too (less manageable to read though):
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name')).prefetch_related('person, hometown, school')
I'm trying to sort (order) by statistical data stored in a ManyToOne relationship. Suppose I have the following code:
class Product(models.Model):
info = ...
data = models.IntegerField(default=0.0)
class Customer(models.Model):
info = ...
purchases = models.ManyToManyField(Product, related_name='customers', blank=True)
class ProductStats(models.Model):
ALL = 0
YOUNG = 1
OLD = 2
TYPE = ((ALL, 'All'), (YOUNG, 'Young'), (OLD, 'Old'),)
stats_type = models.SmallIntegerField(choices=TYPE)
product = models.ForeignKey(Product, related_name='stats', on_delete=models.CASCADE)
data = models.FloatField(default=0.0)
Then I would like to sort the products by their stats for the ALL demographic (assume every product has a stats connected to it for ALL). This might look something like the following:
products = Product.objects.all().order_by('stats__data for stats__stats_type=0')
Currently the only solution I can think of is either to create a new stats class just for all and use a OneToOneField for Product. Or, add a OneToOneField for Product pointing to the ALL stats in ProductStats.
Thank you for your help.
How about like this using multiple fields in order_by:
Product.objects.all().order_by('stats__data', 'stats__stats_type')
# it will order products from stats 0, then 1 then 2
Or if you want to get data for only stats_type 0:
Product.objects.filter(stats__stats_type=0).order_by('stats__data')
You can annotate the value of the relevant demographic and order by that:
from django.db.models import F
Product.objects.all().filter(stats__stats_type=0).annotate(data_for_all=F('stats__data').order_by('data_for_all')
I have a table which looks like this
class Person(User):
"""
This model represents person's personal and
professional details.
"""
attribute1 = models.CharField(max_length=100)
attribute2 = models.TextField()
attribute3 = models.TextField()
attribute4 = models.ForeignKey(Receptionist)
referred_attribute1 = models.ManyToManyField(Hobby)
class Hobby(models.Model):
name = models.CharField(max_length=100)
Use case:
A Person P1 has Hobbies h1,h2,h3(defined[as 3 separate entries] in table Hobby).
Now I want to retrieve a Person object with all the attributes and properties that it has including Hobbies. For that I'm executing the following :
Person.objects.values("attribute1",
"attribute2",
"referred_attribute1").get(attribute3="p1's attribute")
What I want is :
{'attribute1':'p1_attribute1',
'attribute2':'p1_attribute2',
'referred_attribute':['h1','h2','h3']}
and what I get is:
[{'attribute1':'p1_attribute1',
'attribute2':'p1_attribute2',
'referred_attribute':'h1'},
{'attribute1':'p1_attribute1',
'attribute2':'p1_attribute2',
'referred_attribute':'h2'},
{'attribute1':'p1_attribute1',
'attribute2':'p1_attribute2',
'referred_attribute':'h3'}]
Is there a way to get my desired result directly from a queryset? As I do not want to manually re-arrange the above result!
Do this instead:
p1 = Person.objects.get(attribute3="p1's attribute")
p1 is the instance of the person, you can then retrieve all your attributes from it. eg:
p1_attribute1 = p1.attribute1
p1_hobbies = p1.referred_attribute1.all()
Now you can rearrange that data however you like, for example, making a list of the hobbies as follows:
hobby_list = p1_hobbies.values_list('name', flat=True)
I would rename referred_attribute1 to hobbies for code readability
Something like this should work in this case:
[{'attribute1': res.attribute1, 'attribute2': res.attribute2,
'referred_attribute1': [a.name for a in res.referred_attribute1.all()]}
for res in Person.objects.prefetch_related('referred_attribute1').filter(attribute3="p1's attribute")]
Also see Django's Prefetch-related
class Nutrient(models.Model):
tagname = models.CharField(max_length=10)
class FoodNutrientAmount(models.Model):
nutrient = models.ForeignKey(Nutrient)
food = models.ForeignKey(Food)
amount = models.FloatField()
class Food(models.Model):
nutrients = models.ManyToManyField(
Nutrient,
through=FoodNutrientAmount,
)
So, I can get the Foods ordered by the amount of tagname=FOL Nutrient with a list comprehension:
ordered_fnas = FoodNutrientAmount.objects.filter(
nutrient__tagname="FOL"
).order_by('-amount')
ordered_foods_by_most_fol = [fna.food for fna in ordered_fnas]
Can I get such an iterable as a queryset without taking the whole thing into memory?
Maybe there is a different approach using Food.objects.annotate or extra? I can't think of a great way to do it at the moment.
I can get close with values_list; but, I get the ordered list of pks and not the queryset of Food objects that I want.
FoodNutrientAmount.objects.filter(
nutrient__tagname='FOL'
).order_by('-amount').values_list('food', flat=True)
Edit:
This is a Many-to-many relationship. So you can probably leverage that. How about adding default ordering to FoodNutrientAmount and then you can just do normal manytomany queries.
class FoodNutrientAmount(models.Model):
nutrient = models.ForeignKey(Nutrient)
food = models.ForeignKey(Food)
amount = models.FloatField()
class Meta:
ordering = ('-amount',)
Then you can just call -
nutritious_foods = Food.objects.filter(nutrients__tagname='FOL').order_by('foodnutrientamount')
I have a query such that
em =Employer.objects.filter(id=1).annotate(overall_value = Sum('companyreview__overallRating'))
em[0].overall_value
As you see I want to sum of overallRating field of all companyreview objects whose employer has id = 1.
The query above does what I want but I am sure that there is a way to get the sum from an Employer instance.
How can I implement this query like
em =Employer.objects.get(id=1)
rate = em.companyreview_set.all().annotate(overall_value = Sum('overallRating'))
rate.overall_value
?
Thanks
Use aggregate:
e.companyreview_set.aggregate(overall_value = Sum('overall_rating'))
For:
class Employer(models.Model):
name = models.CharField(max_length=100)
class CompanyReview(models.Model):
employer = models.ForeignKey(Employer)
overall_rating = models.IntegerField()