sort django queryset by latest instance of a subset of related model

后端 未结 2 2049
时光取名叫无心
时光取名叫无心 2021-01-20 19:56

I have an Order model and order_event model. Each order_event has a foreignkey to order. so from an order instance i can get: myorder.order_event_set. I want to

相关标签:
2条回答
  • 2021-01-20 20:33

    Ok, I think you can achieve this with the extra method, but not, as far as I can tell, with pure database-agnostic orm. This means you'll have to ensure your sql works for the db backend you're using, and to be wary of django aliasing the table names, but it will also mean you can do it all with one query.

    Something along these lines should work:

    latest_event_subquery = 'select max(event_datetime) ' \
                            'from appname_order_event ' \
                            'where appname_order_event.category="scheduling" and ' \
                                  'appname_order_event.event_id=appname_order.id'
    queryset = Order.objects.extra(select={'latest_event_date': latest_event_subquery}).order_by('latest_event_date')
    

    Does that make sense?

    0 讨论(0)
  • 2021-01-20 20:44

    Greg's answer is great, and I used it for awhile. However, I wanted to access other fields of latest_event. So, I ended up storing the latest_event as a field of Order:

    # The latest event
    latest_event = db.ForeignKey('whateverapp.Event', editable=False, null=True)
    

    Then I set up a signal to recalculate the latest event upon save:

    @receiver(post_save, sender=Event)
    def visit_calculate_latest(sender, instance, **kwargs):
        """Recalculate latest event"""
        instance.parent.latest_event = instance.parent.get_latest_event()
    

    where get_latest_event() did the query:

    def get_latest_event(self):
        """Return most recent event or None."""
        try:
            return Event.objects.filter(
                parent=self.id).order_by('-event_date', '-id')[0]
        except IndexError:
            return None
    

    Now I can filter by latest_event__whatever:

        return qs.filter(qobjs).order_by('-latest_event__event_date',
            '-latest_event__pk')
    
    0 讨论(0)
提交回复
热议问题