39👍
As far as I know, there is no one-step way of doing this in Django ORM, but you can split it into two queries:
from django.db.models import Max
bakeries = Bakery.objects.annotate(
hottest_cake_baked_at=Max('cake__baked_at')
)
hottest_cakes = Cake.objects.filter(
baked_at__in=[b.hottest_cake_baked_at for b in bakeries]
)
If id’s of cakes are progressing along with bake_at timestamps, you can simplify and disambiguate the above code (in case two cakes arrives at the same time you can get both of them):
from django.db.models import Max
hottest_cake_ids = Bakery.objects.annotate(
hottest_cake_id=Max('cake__id')
).values_list('hottest_cake_id', flat=True)
hottest_cakes = Cake.objects.filter(id__in=hottest_cake_ids)
BTW credits for this goes to Daniel Roseman, who once answered similar question of mine:
If the above method is too slow, then I know also second method – you can write custom SQL producing only those Cakes, that are hottest in relevant Bakeries, define it as database VIEW, and then write unmanaged Django model for it. It’s also mentioned in the above django-users thread. Direct link to the original concept is here:
Hope this helps.
41👍
Starting from Django 1.11
and thanks to Subquery and OuterRef, we can finally build a latest-per-group
query using the ORM
.
hottest_cakes = Cake.objects.filter(
baked_at=Subquery(
(Cake.objects
.filter(bakery=OuterRef('bakery'))
.values('bakery')
.annotate(last_bake=Max('baked_at'))
.values('last_bake')[:1]
)
)
)
#BONUS, we can now use this for prefetch_related()
bakeries = Bakery.objects.all().prefetch_related(
Prefetch('cake_set',
queryset=hottest_cakes,
to_attr='hottest_cakes'
)
)
#usage
for bakery in bakeries:
print 'Bakery %s has %s hottest_cakes' % (bakery, len(bakery.hottest_cakes))
- [Django]-Printing Objects in Django
- [Django]-Django proxy model and ForeignKey
- [Django]-Add rich text format functionality to django TextField
24👍
If you happen to be using PostGreSQL, you can use Django’s interface to DISTINCT ON:
recent_cakes = Cake.objects.order_by('bakery__id', '-baked_at').distinct('bakery__id')
As the docs say, you must order by
the same fields that you distinct on
. As Simon pointed out below, if you want to do additional sorting, you’ll have to do it in Python-space.
- [Django]-Django content-type : how do I get an object?
- [Django]-Why is assertDictEqual needed if dicts can be compared by `==`?
- [Django]-Check if key exists in a Python dict in Jinja2 templates
5👍
This should do the job:
from django.db.models import Max
Bakery.objects.annotate(Max('cake__baked_at'))
- [Django]-Problems with contenttypes when loading a fixture in Django
- [Django]-Django's self.client.login(…) does not work in unit tests
- [Django]-How to change User representation in Django Admin when used as Foreign Key?
4👍
I was fighting with similar problem and finally come to following solution. It does not rely on order_by
and distinct
so can be sorted as desired on db-side and also can be used as nested query for filtering. I also believe this implementation is db engine independent, because it’s based on standard sql HAVING
clause. The only drawback is that it will return multiple hottest cakes per bakery, if they are baked in that bakery at exactly same time.
from django.db.models import Max, F
Cake.objects.annotate(
# annotate with MAX "baked_at" over all cakes in bakery
latest_baketime_in_bakery=Max('bakery__cake_set__baked_at')
# compare this cake "baked_at" with annotated latest in bakery
).filter(latest_baketime_in_bakery__eq=F('baked_at'))
- [Django]-Is there a way to filter a queryset in the django admin?
- [Django]-Django: How to check if the user left all fields blank (or to initial values)?
- [Django]-How to submit form without refreshing page using Django, Ajax, jQuery?
0👍
Cake.objects.filter(bakery__town="Anytown").order_by("-created_at")[:1]
I haven’t built out the models on my end, but in theory this should work. Broken down:
Cake.objects.filter(bakery__town="Anytown")
Should return any cakes whom belong to “Anytown”, assuming the country is not part of the string. The double underscores betweenbakery
andtown
allow us to access thetown
property ofbakery
..order_by("-created_at")
will order the results by their created date, most recent first (take note of the-
(minus) sign in"-created_at"
. Without the minus sign, they’d be ordered by oldest to most recent.[:1]
on the end will return only the 1st item in the list which is returned (which would be a list of cakes from Anytown, sorted by most recent first).
Note: This answer is for Django 1.11.
This answer modified from Queries shown here in Django 1.11 Docs.
- [Django]-What is the difference between null=True and blank=True in Django?
- [Django]-Django models avoid duplicates
- [Django]-Django Rest JWT login using username or email?
0👍
@Tomasz Zieliński solution above did solve your problem but it did not solve mine, because I still need to filter the Cake. So here is my solution
from django.db.models import Q, Max
hottest_yellow_round_cake = Max('cake__baked_at', filter=Q(cake__color='yellow', cake__shape='round'))
bakeries = Bakery.objects.filter(town='Chicago').annotate(
hottest_cake_baked_at=hottest_yellow_round_cake
)
hottest_cakes = Cake.objects.filter(
baked_at__in=[b.hottest_cake_baked_at for b in bakeries]
)
With this approach, you can also implement other things like Filter, Ordering, Pagination for Cakes
- [Django]-Django 1.5 custom User model error. "Manager isn't available; User has been swapped"
- [Django]-How to allow users to change their own passwords in Django?
- [Django]-Altering one query parameter in a url (Django)