17

私は次のモデルを持っています:

class Assignment(models.Model):
  extra_days = models.IntegerField(default=0)
  due_date = models.DateTimeField()

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'))

を印刷すると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'

たとえば、3.1 日という結果になる時差を行う場合、日差はまだ 3 であると想定しています。次のようなことを行う方が正しいと思います。

a = Assignment.objects.filter(due_date__gt=cur_date - timedelta(days=F('extra_days')))

しかし、それもエラーになります。

生の SQL クエリを作成せずにこれを行うにはどうすればよいですか?

4

4 に答える 4

4

私がやろうとしていることは不可能のようです。私は生のクエリを書くことになりました:

cursor.execute("SELECT * FROM app_assignment WHERE DATE_ADD(due_date, INTERVAL extra_days DAYS) > utc_timestamp()")

ORM を使用して一見単純に見えることを実行できないことに非常に反発したため、SQLAlchemy を試してみることを検討しましたが、生のクエリは問題なく動作します。私は常に ORM を使用できるようにするための回避策を試みましたが、今後は複雑なクエリには未加工の SQL を使用します。

于 2013-09-03T02:58:50.553 に答える
4

これは、使用しているデータベース バックエンド (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')))

これにより、次の 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"))

他のデータベース バックエンドでの日付差の計算については、DatediffMichael Brooks によって作成された関数を参照してください。

于 2018-08-30T18:26:19.110 に答える
3

私の知る限り、F() オブジェクトを別の関数にパラメーターとして渡すことはできません。これは、F() 基本クラスがツリーであるためです。 .

F() define atdjango/db/models/expression.pyおよび Node at django/utils/tree.py(django 1.3.4)を参照してください。

class ExpressionNode(tree.Node):
    ...

class F(ExpressionNode):
    """
    An expression representing the value of the given field.
    """
    def __init__(self, name):
        super(F, self).__init__(None, None, False)
        self.name = name

    def __deepcopy__(self, memodict):
        obj = super(F, self).__deepcopy__(memodict)
        obj.name = self.name
        return obj

    def prepare(self, evaluator, query, allow_joins):
        return evaluator.prepare_leaf(self, query, allow_joins)

    def evaluate(self, evaluator, qn, connection):
        return evaluator.evaluate_leaf(self, qn, connection)

あなたは次のようなことができます

Assignment.objects.filter(due_date__gt=F('due_date') - timedelta(days=1))

だがしかし

Assignment.objects.filter(due_date__gt=cur_date - timedelta(days=F('extra_days')))

私が間違っていた場合は修正してください。この小さな助けを願っています。

于 2013-09-01T18:25:32.957 に答える
2

他の誰かがこれを探している場合に備えて、調べる価値のあるものがあります。

私は Django 1.4 を使用していますが、OP とまったく同じ問題が発生しています。問題はおそらくデータベースに送信される前に評価する必要があるためであると思われますが、timedeltaオブジェクトは本質的にデータベースでのみ解決されます。datetimeF

Django 1.8 で、Python の timedelta のように直接動作するように見える新しいDurationFieldが導入されたことに気付きました。これは、F オブジェクトの timedelta を IntegerField でルックアップする必要がある代わりに、理論的には DurationField を使用でき、F オブジェクトが timedelta にある必要がまったくないことを意味するはずです。残念ながら、依存関係のため、現在、プロジェクトを 1.8 にアップグレードしてこの理論をテストすることはできません。

他の誰かがこの問題に遭遇し、私の提案をテストできる場合は、知りたいです. 依存関係を解決して 1.8 にアップグレードできる場合は、必ず結果を投稿します。

于 2016-02-02T03:12:06.013 に答える