通过相关模型子集的最新实例对django queryset进行排序

时间:2012-12-07 05:01:29

标签: django django-queryset django-aggregation django-related-manager

我有一个Order模型和order_event模型。每个order_event都有一个要订购的外键。所以从订单实例我可以得到:myorder.order_event_set。我想获得所有订单的列表,但我希望它们按最后一个事件的日期排序。像这样的语句可以按最新的事件日期排序:

queryset = Order.objects.all().annotate(
    latest_event_date=Max('order_event__event_datetime')
    ).order_by('latest_event_date')

然而,我真正需要的是按照事件的最新日期排序的所有订单的列表。例如,我的事件被分类为“调度”,“处理”等。因此,我应该能够获得按最新调度事件排序的所有订单的列表。这个django doc(https://docs.djangoproject.com/en/dev/topics/db/aggregation/#filter-and-exclude)显示了我如何使用过滤器获取最新的计划事件,但这排除了没有计划的订单事件

我以为我可以将过滤后的查询集与一个查询集合在一起,该查询集包含那些缺少调度事件的订单......但我不太清楚如何做到这一点。我看到了与使用python列表相关的答案,但是拥有一个合适的django查询集(即对于带有分页的视图等)会更有用。

编辑:评论/建议

class Order(models.Model):
    desc = models.CharField(max_length=30)

class Order_event(models.Model):
    order = models.ForeignKey(Order)
    event_datetime = models.DateTimeField(auto_now_add = True)

另外,我不介意在多个声明中这样做。此外,通过python而不是orm进行排序等是可以的,因为我不使用庞大的数据集。如果可能的话,我会因为你提到的原因而远离sql。结合单独的,排序的查询集看起来很有希望,但我遇到了困难。

2 个答案:

答案 0 :(得分:1)

好的,我认为您可以使用extra方法实现此目的,但据我所知,不能使用纯数据库无关的方法。这意味着您必须确保您的sql适用于您正在使用的db后端,并且要警惕django别名表名称,但这也意味着您可以使用一个查询完成所有操作。

这些方面应该有效:

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')

这有意义吗?

答案 1 :(得分:0)

格雷格的答案很棒,我用了一段时间。但是,我想访问latest_event的其他字段。所以,我最终将latest_event存储为Order的字段:

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

然后我设置了一个信号,以便在保存时重新计算最新事件:

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

其中get_latest_event()执行查询:

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

现在我可以通过latest_event__whatever过滤:

    return qs.filter(qobjs).order_by('-latest_event__event_date',
        '-latest_event__pk')