【发布时间】:2019-11-26 22:49:34
【问题描述】:
在 Django 中,我正在创建一个带有 CASE 和注释的查询集。它看起来像这样:
days_diff_calc = Case(
When(Q(sent_date__isnull=True),
then=None),
When(Q(received_date__isnull=True),
then=(timezone.now().date() - F('sent_date'))),
default=(F('received_date') - F('sent_date')),
output_field=DurationField()
)
Item.objects.all().annotate(
days_diff=days_diff_calc
)
它创建的查询的重要部分如下所示:
CASE
WHEN "item"."sent_date" IS NULL THEN NULL
WHEN "item"."received_date" IS NULL THEN ('2019-11-26' - "item"."sent_date")
ELSE (interval '1 day'* ("item"."received_date" - "item"."sent_date"))
END AS "days_diff"
在 Postgres 中运行时出现此错误:
CASE types interval and integer cannot be matched
LINE 3: ...item"."received_date" IS NULL THEN ('2019-11-2...
^
似乎出于某种原因,Django ORM 在 ELSE 之后添加了 interval 1 day *,但在第二个 WHEN 之后没有这样做,我认为这就是这个错误的原因。我不明白 - 为什么它只将它添加到一个地方而不是另一个地方,如果我想将它添加到另一个地方(第二个 WHEN) - 我会这样做吗?
编辑:
django 版本 2.1.5, psycopg2 版本 2.6.2, PostgreSQL 9.6
所有“日期”字段的类型均为models.DateField(null=True, blank=True)
也尝试使用 ExpressionWrapper 并得到相同的结果:
days_diff_calc = Case(
When(Q(sent_date__isnull=True),
then=None),
When(Q(received_date__isnull=True),
then=ExpressionWrapper(timezone.now().date() - F('sent_date'),
output_field=DurationField())),
default=ExpressionWrapper(F('received_date') - F('sent_date'),
output_field=DurationField()),
)
【问题讨论】:
-
我至今无法复制这个。你使用的是什么版本的 django 和 Postgres?另外:你能展示你的项目模型的相关部分吗?同时:您可以尝试将有问题的表达式包装在
ExpressionWrapper调用中以强制使用output_field类型。 -
@RishiG 添加了所需信息。
标签: django postgresql django-annotate