简体   繁体   中英

django sort queryset by newest dates from different fields

How can I sort queryset just like forums do?

I mean ordering by one date field, and there will be another order date to use for sorting, for example in forums: subjects get sorted by on created date (or updated date), but if any old subject got a new reply, then it will be shown before other subjects. This is exactly what I'm trying to do.

What I tried so far:

    subjects = Subjects.objects.filter(active=True).order_by('-sticky', '-updated_date', 'reply__updated_date')

but in this case results are repeated as reply counts.

I've also tried:

    subjects = Subjects.objects.filter(active=True).order_by('-sticky', '-updated_date').order_by('reply__updated_date')

but in this case the second order_by overrides the first one.

Is there any guideline to follow?

BTW, I'm pretty sure you got it, but just to be clear, Subject is a model and Reply is another model, connected by a foreign key.

If I got it correctly, you can achieve this by using annotations and database functions .

One thing at a time.

  1. You want to sort Subjects by reply date in descending order: in Django's own terms, you need to annotate() each Subjects with the maximun updated_date of its related model reply , and sort Subjects by the new field in reverse order, like this:

     from django.db.models import Max subjects = Subject.objects.annotate(lr=Max('reply__updated_date'))\\ .order_by('-lr') 
  2. Now you have all subjects with at least one reply sorted, but what about the subjects without replies ?

    We can rephrase our sorting like this: "sort by last reply date if there are replies, and by last subject update otherwise ".

    The "otherwise" part can be achieved by the Coalesce() function, which replaces NULLs with another expression of our choice. In our case it'll replace what's inside Max() with the updated_date field of the Subjects :

     from django.db.models import Max from django.db.models.functions import Coalesce subjects = Subject.objects\\ .annotate(lr=Coalesce(Max('reply__updated_date'), 'updated_date'))\\ .order_by('-lr') 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM