使用F和Q表达式进行Django模型过滤

时间:2015-06-16 13:44:13

标签: django django-models django-filter

我正在Django中制作一个调度程序,并且在每周日历视图中过滤我的事件时遇到问题。日历支持多日事件,并且我当前的过滤器不适用于此每周视图。

这是我的模特:

 class Event(models.Model):
    title = models.CharField(max_length=40)
    start = models.DateTimeField()
    end = models.DateTimeField()
    description = models.TextField()
    all_day = models.BooleanField(default=False)
    recuring = models.BooleanField(default=False)
    recuring_end = models.DateTimeField(blank=True, null=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return '/cab/event/%i/' % self.id

我试图过滤给定周内发生的事件。对于单日活动,我会做类似的事情。

events = Event.objects.order_by('start').filter(Q(start__gte=monday) | Q(end__lte=sunday))

这可以检索一周内发生的所有单日事件。它也适用于在给定周内开始或停止的多日活动。问题是检索在一周之前开始并在一周之后结束的对象,但确实跨越一周。

我的想法是尝试过滤掉任何超过9天的事件(即,将从前一周的星期日开始并在下周一的星期一结束),因为我知道这些是罕见的并且不会完全破坏性能。我想这样做而不指定日期范围,因为这不是动态的。

为了尝试最小化性能影响,我试图使用F表达式来评估事件的开始和结束事件的持续时间。我的第一个想法是做一些像:

my_events = Event.objects.order_by('start').filter(Q(start__gte=monday) | Q(end__lte=sunday) | Q( (F('end_day') - F('start_day')) >= 9 ) )

但我收到错误'bool' object is not iterable

也尝试过:

my_events = Event.objects.order_by('start').filter(Q(start__gte=monday) | Q(end__lte=sunday) | Q( (F('end_day') - F('start_day')) >= datetime.timedelta(days=9) ) )

但获得can't compare datetime.timedelta to ExpressionNode

任何人都煽动如何做这样的事情?

3 个答案:

答案 0 :(得分:2)

from datetime import timedelta

Event.objects.filter(end__gt=F('start') + timedelta(days=9))

文档有example

更新:

超过9天的事件(由周一晚开始或比周日早结束),按start排序。

(Event.objects
 .filter(end__gt=F('start') + timedelta(days=9),
         Q(start__gte=monday) | Q(end__lte=sunday))
 .order_by('start'))

答案 1 :(得分:1)

我认为Arrow可能对你的任务有所帮助。

也许精通的人可以为您提供准确的代码,但与此同时,这段视频可能有所帮助:

https://godjango.com/72-using-arrow-for-better-datetime/

答案 2 :(得分:0)

只需警告@ https://stackoverflow.com/users/4907653/f43d65 的答案是,最后一个带有Q对象的查询查找可能无效。

Reference to docs

查阅功能可以混合使用Q对象和关键字参数。提供给查找功能的所有参数(无论是关键字参数还是Q对象)都“与”在一起。但是,如果提供了Q对象,则它必须在任何关键字参数的定义之前。例如:

Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who',)

…将是一个有效的查询,等同于前面的示例;但是:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

...无效。