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

3
我是一个 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) ) )

但是出现了无法将datetime.timedelta与ExpressionNode进行比较

有人知道如何解决这个问题吗?


@sobolevn 不是重复的,因为我不想指定日期范围。 - Philippe Fisher
Q函数只能与=一起使用,不能与>=一起使用,这就是为什么会出现错误'bool' object is not iterable - Sylvain Biehler
Q(end_day__gte=start_day+9)不起作用吗? - Sylvain Biehler
@SylvainBiehler 不是特别想要9天,而是9天或更多。是否有Q函数>=的替代方法? - Philippe Fisher
__gte代表大于或等于。 - Sylvain Biehler
2个回答

5
from datetime import timedelta

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

文档中有一个 示例,与it技术有关。

更新:

事件跨越超过9天并且(开始晚于星期一或结束早于星期日),按start排序。

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

0

提醒一下 @https://stackoverflow.com/users/4907653/f43d65 的回答,最后一个查询使用 Q 对象可能无效。

文档参考

查找函数可以混合使用 Q 对象和关键字参数。提供给查找函数的所有参数(无论是关键字参数还是 Q 对象)都会“AND”在一起。但是,如果提供了 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))
)

...将无效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接