Django QuerySet过滤器获取截止date_time之前的最后一个对象

时间:2019-07-03 13:41:17

标签: django

我正在尝试在构建QuerySet时保持惰性(未评估),而我的目标是在给定日期之前找到最后一个事件。

class Event(models.Model):
    date_time = models.DateTimeField('Date and time of event')

    class Meta:
         ordering = ['-date_time']

现在我有一个截止日期date_time,我可以通过以下方法轻松获得截止日期之后的所有活动:

events = Event.objects.filter(date_time__gte=cut_off)

现在我也想在cut_off之前加入最后一个活动!

我可以想到多种方法来导致数据库命中,但是我想找到一种使QuerySet保持惰性的解决方案。

一个明显的候选者是窗口滞后功能。如果我们用下一个事件的date_time注释事件,则从概念上讲这样的事情会起作用:

window_lag = Window(expression=Lag("date_time"),
                    order_by=F("date_time").desc())

annotated_events = Event.objects.annotate(date_time_next=window_lag)
events = annotated_events.filter(date_time_next__gte=cut_off)

但是a还不合法:

https://code.djangoproject.com/ticket/28333

可以通过使用原始SQL来完成(而且我已经做到了),但还是如此。我想尽可能保持整洁,并保持QuerySet的懒惰(构建时没有数据库命中)。

是否有任何创造性的方式来编写不使用窗口函数的过滤器,可以保持懒惰,但仍能达到在cut_off之后和之前的所有事件返回所有事件的预期结果?

我们不知道该事件与截止日期之间经过了多少时间,可能是几秒钟,可能是几年,那里没有任何可能的假设,我们所知道的是,下一个..就是全部。

也许某些结构如下:

events = Event.objects.filter(Q(date_time__gte=cut_off)|Q(...))

第二个Q对象以某种方式创造性地添加了所需事件。

1 个答案:

答案 0 :(得分:0)

结果证明,仅对Q个对象而言,这并不太可行,但对联合而言,它是:

events = Event.objects.filter(date_time__gte=cut_off)
extra_event = Event.objects.filter(date_time__lt=cut_off)[:1]
events = events.union(extra_event)

这仍然是懒惰和优雅的ORM实现。

我不确定使用Window Lag批注将其与性能进行比较,但是直到在Django中可以对其进行过滤之前,这还是不是一个优雅的ORM选项。