> prop_dates = Target.objects.annotate(latest_property=Max('property__export_date')).values_list('latest_property', flat=True)
> properties = Property.objects.filter(export_date__in=prop_dates)
Note that if prop_dates has more than 10-15 entries, it's going to perform badly (at least on PostgreSQL, and almost certainly on MySQL too). I think this particular situation is definitely a .raw() opportunity.
--
-- Christophe Pettus
x...@thebuild.com
Tim Shaffer's response would have you doing N+1 queries, and having to loop through all of your Target objects in-memory. Technically it would work, but as soon as you have a decently sized amount of data in there it'd slow to a crawl.
The best way I can see to do this straight with the Django ORM is:prop_dates = Target.objects.annotate(latest_property=Max('property__export_date')).values_list('latest_property', flat=True)properties = Property.objects.filter(export_date__in=prop_dates)
Which comes out to two queries. If you absolutely had to, you could execute some raw SQL to narrow it down to one query. Please note that there is a (very) small possibility that the second query might return extra Properties for a given Target. Because it's operating based on date-timestamps, there could be two Properties that happen to have the exact same export_date, one of which happens to be the most recent for a given Target. Eliminating those duplicates, if you want to account for that scenario, can be done in-memory or I believe through some adjustments to the second line above.
Not sure I understand the limitation to 10-15 entries. Please explain?
Or EXPLAIN?
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--from django.db.models import Max
The best way I can see to do this straight with the Django ORM is:prop_dates = Target.objects.annotate(latest_property=Max('property__export_date')).values_list('latest_property', flat=True)properties = Property.objects.filter(export_date__in=prop_dates)Let say I have two targets which I'll call target1 and target2.Target1 have a property for yesterday and one for today. Target2 only have a property for yesterday. Both yesterday and today will be included in prop_dates since they are the latest for at least one target. And then Target1 will have two entries in properties while it should only have one for today.
> Not sure I understand the limitation to 10-15 entries.
That's my rule of thumb as to when I prefer to re-express a query as a join rather than an IN. Larger values can work just fine, but __in in Django tends to be abused with gigantic inclusion sets.
> I don't understand the 10-15 limit either. I've done giant "in" queries in the past that perform fine with large data sets and proper indexing.
You can set the rule of thumb whereever you like; eventually, the curves between an IN and a join will cross, however.