[英]How can I filter a Django queryset using just a CASE or a COALESCE expression?
我将 Django 查询集基于具有以下 WHERE 条件的功能性 postgres 查询:
... WHERE COALESCE("project_story"."owner_id" = [INSERT_USER_ID], "project_story"."published_date" IS NOT NULL)
英文:如果用户是故事的所有者,则包含故事。 如果用户不是所有者并且故事未发布,则将其排除。
理想情况下,Django ORM 应该允许以下内容:
queryset = queryset.filter(
Coalesce(
Q(owner_id=user.id),
Q(published_date__isnull=False)
)
)
但是在执行时,Django 会抛出错误:
TypeError:“Coalesce”对象不可迭代
不幸的是,我需要在数据库级别进行条件过滤。
是否有允许使用 Coalesce 表达式进行选择的符号或方法?
我不想使用 rawsql 或 queryset.extra。
这是我自己想出来的。 由于尚未发布真正的答案,这是我的解决方案:
return queryset.all().annotate(
viewable=Case(
When(owner_id=user.id, then=True),
When(published_date__isnull=False, then=True),
default=False,
output_field=db.models.BooleanField()
),
).filter(
viewable=True
)
相当难以阅读,不是吗? 生成的 SQL 也同样丑陋:
AND CASE WHEN ("project_story"."owner_id" = [INSERT USER ID]) THEN True WHEN ("project_story"."published_date" IS NOT NULL) THEN True ELSE False END = True) ORDER BY "project_story"."image_count" DESC
尽管使用 CASE 会导致与原始查询相同的结果,但我仍然希望使用不那么冗长的代码。
在那之前,我会将我的问题标记为已回答。
用于为 COALESCE() 编写自己的 Expression 类的代码片段的微小开头,请参阅下面的官方文档链接以获取完整源代码。
注意:并非所有数据库都有 COALESCE(),我认为这就是为什么这不是官方表达式的原因。 可能可以编写一些代码将其转换为标准 Case(...) 表达式作为后备,然后使用 COALESCE() 进行特定于 db 的 sql 转换。 我把它作为练习留给读者;-)
from django.db.models import Expression
class Coalesce(Expression):
template = 'COALESCE( %(expressions)s )'
...
完整代码的官方文档: Django Models - Writing your own Query Expressions
我相信 Q() 的结果总是 True 或 False,所以在 Coalesce 表达式中使用它是行不通的。 解决方案是使用条件表达式,结合 Case 和 filter。 您可以在文档中找到所需的所有信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.