Django过滤列之间的日期差异

Posted

技术标签:

【中文标题】Django过滤列之间的日期差异【英文标题】:Django filter on date difference between columns 【发布时间】:2018-11-09 01:31:56 【问题描述】:

作为 Django 初学者,我遇到了一个非常基本的问题:根据两列的日期差异过滤表。我可以用原始 SQL 解决这个问题,但我真的很想使用基本的 Django 函数。

我有以下型号:

  from django.db import models
  import datetime

  class Race(models.Model):
      __tablename__ = 'race'
      name = models.CharField(max_length=200)
      country = models.CharField(max_length=100, null=True)
      start = models.DateField()
      end = models.DateField()

我想提取持续的比赛,例如超过 5 天。我可以通过某种方式获得一个 timediff 列:

Race.objects.annotate(tdiff=F('end')-F('start')).first()
set1 = Race.objects.annotate(tdiff=F('end')-F('start')).all()
set1.first().tdiff

现在,我如何过滤此列,我尝试的是:

min_diff = datetime.timedelta(5)
set1.filter(tdiff__gte=5).first()
set1.all().filter(tdiff__gte=min_diff)
set1.filter(tdiff__gte=min_diff).first()

但这一切都给出了:

TypeError:预期的字符串或类似字节的对象

然后我考虑使用 extra 来获取 where 子句:

set2 = Race.objects.annotate(tdiff=F('end')-F('start'))
set2.first().tdiff
set2.all().extra(where=['tdiff>=5'])

导致:

ProgrammingError:列“tdiff”不存在

同一方向的问题包括this one 和this one,但没有一个真正给出过滤新列(此处为 tdiff)的解决方案。


当最终确定这个问题时,我最终确实得到了我想要的结果:

Race.objects.filter(end__gte=F("start")+5)
print(Race.objects.filter(end__gte=F("start")+5).query)

但我还是很想知道如何利用这个临时列 tdiff。

谢谢!


回答后更新

接受的答案正是我想要的:

from django.db.models import DurationField, F, ExpressionWrapper
import datetime

set4 = Race.objects.annotate(    
    diff=ExpressionWrapper(F('end') - F('start'), output_field=DurationField())).filter(
    diff__gte=datetime.timedelta(5))
len(set4)
# 364
len(Race.objects.filter(end__gte=F("start")+5))
# 364

【问题讨论】:

应用你的F()函数后tdiffoutput_field类型是什么?我的猜测是,由于您的 startend 字段是 DateTime,因此您必须使用 ExpressionWrappertdiffoutput_field 指定为 DurationField。然后,您应该能够针对 python 的 timedelta 类型在字段上运行过滤器。 Race.objects.annotate(tdiff=ExpressionWrapper(F('end')-F('start'), output_field=DurationField())) 【参考方案1】:

这会很神奇:

from django.db.models import DurationField, F, ExpressionWrapper
import datetime

Race.objects.annotate(
    diff=ExpressionWrapper(F('end') - F('start'), output_field=DurationField())
).filter(diff__gte=datetime.timedelta(5))

这将返回所有持续时间大于或等于5Race实例

参考资料:

ExpressionWrapper 所以发帖-How should I use DurationField in my model?-

【讨论】:

谢谢;这行得通!我将用结果更新问题,并表明它给出的结果与我的基本解决方案相同。

以上是关于Django过滤列之间的日期差异的主要内容,如果未能解决你的问题,请参考以下文章

Laravel,两列之间的日期范围过滤器

c# - 如何过滤包含单词和日期的日期列之间的datagridview?

django个人过滤器日期时间

开始日期结束日期列上的 JSON Linq.js 过滤器

使用AGGREGATE函数过滤掉$ 0的所有订单

如何在 django 中按日期范围过滤记录?