I've Django models setup within the following manner:
model A includes a one-to-many relationship to model B
each record inside a has between 3,000 to fifteen,000 records in B
What's the easiest method to create a query which will retrieve the latest (finest pk) record in B that matches an archive inside a for every record inside a? Is something which I have to use SQL for instead of the Django ORM?
Produce a assistant function for securely removing the 'top' item from the queryset. I personally use this everywhere during my own Django applications.
def top_or_none(queryset): """Safely pulls off the top element in a queryset""" # Extracts a single element collection w/ top item result = queryset[0:1] # Return that element or None if there weren't any matches return result if result else None
This uses a little of the trick w/ the slice operator to add a limit clause onto your SQL.
Are now using this function anywhere you need the 'top' item of the query set. Within this situation, you need to obtain the top B item for any given A in which the B's are sorted by climbing down pk, as a result:
latest = top_or_none(B.objects.filter(a=my_a).order_by('-pk'))
Additionally, there are the lately added 'Max' function in Django Aggregation that could help give you the max pk, however i can't stand that solution within this situation because it adds complexity.
P.S. I do not enjoy depending around the 'pk' area for this kind of query as some RDBMSs don't guarantee that consecutive pks is equivalent to logical creation order. If I've got a table which i know I will have to query in this way, It's my job to have my very own 'creation' datetime column will be able to use to buy by rather than pk.
Edit according to comment:
If you would rather use queryset, you are able to customize the 'top_or_none' function thusly:
def top_or_none(queryset): """Safely pulls off the top element in a queryset""" try: return queryset except IndexError: return None
I did not propose this initially because I had been of the opinion that queryset would withdraw the whole result set, then go ahead and take 0th item. Apparently Django adds a 'LIMIT 1' within this scenario too, therefore it is a secure option to my slicing version.
Obviously you can also make the most of Django's related manager construct here and make the queryset using your 'A' object, based on your choice:
latest = top_or_none(my_a.b_set.order_by('-pk'))
I do not think Django ORM can perform this (but I have been amazed before...). If there is a reasonable quantity of An archive (or maybe you are paging), I'd just add a means to One that will return this 'newest' B record. If you wish to get lots of A records, each with it's own latest B, I'd drop to SQL.
recall it does not matter which route you are taking, you will need a appropriate composite index on B table, maybe adding an
order_by=('a_fk','-id') towards the