Django与F对象的时差

use*_*706 15 django

我有以下型号:

class Assignment(models.Model):
  extra_days = models.IntegerField(default=0)
  due_date = models.DateTimeField()
Run Code Online (Sandbox Code Playgroud)

due_date分配到期的日期在何处,是在extra_days完成分配的截止日期之后给出的额外天数.

我想创建一个查询,返回due_date + extra_days大于当前日期的所有行.这就是我在做的事情:

from django.utils import timezone
from django.db.models import F
from datetime import datetime

cur_date = timezone.make_aware(datetime.now(), timezone.get_default_timezone())
a = Assignment.objects.filter(extra_days__gt=cur_date - F('due_date'))
Run Code Online (Sandbox Code Playgroud)

当我打印时a,我收到以下错误:

  File "c:\Python27\lib\site-packages\MySQLdb\cursors.py", line 204, in execute
    if not self._defer_warnings: self._warning_check()
  File "c:\Python27\lib\site-packages\MySQLdb\cursors.py", line 117, in _warning
_check
    warn(w[-1], self.Warning, 3)
Warning: Truncated incorrect DOUBLE value: '2013-09-01 02:54:31'
Run Code Online (Sandbox Code Playgroud)

如果我做了导致3.1天的时差,我假设天差仍然是3.我认为做这样的事情会更正确:

a = Assignment.objects.filter(due_date__gt=cur_date - timedelta(days=F('extra_days')))
Run Code Online (Sandbox Code Playgroud)

但这也会导致错误.

如何在不编写原始SQL查询的情况下执行此操作?

mrt*_*rts 6

这取决于您使用的数据库后端,似乎是 PostgreSQL。

PostgreSQL 可以直接减去日期,所以下面的代码可以工作:

from django.db.models import F, Func
from django.db.models.functions import Now

class DaysInterval(Func):
    function = 'make_interval'
    template = '%(function)s(days:=%(expressions)s)'

qs = Assignment.objects.annotate(remaining_days=F('due_date') - Now())
qs.filter(remaining_days__lt=DaysInterval(F('extra_days')))
Run Code Online (Sandbox Code Playgroud)

这会产生以下 SQL:

SELECT "assignments_assignment"."id", 
       "assignments_assignment"."extra_days", 
       "assignments_assignment"."due_date", 
       ("assignments_assignment"."due_date" - STATEMENT_TIMESTAMP()) AS "remaining_days" 
FROM   "assignments_assignment" 
WHERE  ("assignments_assignment"."due_date" - STATEMENT_TIMESTAMP())
        < (make_interval(DAYS:="assignments_assignment"."extra_days"))
Run Code Online (Sandbox Code Playgroud)

对于其他数据库后端中的日期差异计算,请参阅DatediffMichael Brooks 创建的函数。


use*_*706 5

似乎我正在尝试做的事情是不可能的.我最后写了一个原始查询:

cursor.execute("SELECT * FROM app_assignment WHERE DATE_ADD(due_date, INTERVAL extra_days DAYS) > utc_timestamp()")
Run Code Online (Sandbox Code Playgroud)

我因为无法使用ORM来做一些看起来很简单而我考虑尝试SQLAlchemy的东西而感到震惊,但原始查询工作得很好.我总是尝试使用变通方法以确保我可以使用ORM,但我会使用原始SQL进行复杂查询.