简体   繁体   中英

How to sort a queryset of different models in Wagtail/Django?

I have a Wagtail site and I'm making a listing page for a few different Page types/Content types. I filter by a snippet field first:

def highlights_list(category='Highlight'):
    tag = ContentCategory.objects.get(name=category)
    highlights = Page.objects.filter(
        Q(event__categories=tag)|
        Q(newspage__categories=tag)|
        Q(contentpage__categories=tag)).live()
    return highlights.order_by('-last_published_at')

In Wagtail all content types inherit from the base Page class which makes creating a queryset with all the content types I want really easy. But I can't work out how to sort nicely.

Sorting by last_published_at is fine for NewsPage and ContentPage but not for Event where I'd like to sort by the DateTimeField for the event.

I thought about making a @property on all the models called sort_date which uses the datetime field specific to each model that I'd like to sort on, but that just doesn't work.

Any suggestions are very welcome!

I can think of two solutions for this, but only one seems to be easier to do. I changed your function above to this:

def highlights_list(category='Highlight'):
    tag = ContentCategory.objects.get(name=category)
    highlights = Page.objects.filter(
        Q(event__categories=tag)|
        Q(newspage__categories=tag)|
        Q(contentpage__categories=tag)
    ).live().specific()

    return sorted(
        highlights,
        key=lambda p: getattr(p, 'date') or getattr(p, 'last_published_at'),
        reverse=True
    )

What this does is it takes all the pages from highlights and sorts them based on the value in date or last_published_at as if they're the same field. Because only the Event page has a date field, last_published_at is used as the fallback, a field all live pages have in common. If you leave out specific() in your queryset like in your question, it throws an AttributeError saying 'Page' object has no attribute 'date' .

As a bonus, the sorting part doesn't use any database queries since it is done in Python. Note that this returns a list based on the original QuerySet .

The second solution involves database transactions and Wagtail hooks and has more code, but that is something I don't want to share as I haven't thought of how to write that out.

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