繁体   English   中英

如何仅使用 CASE 或 COALESCE 表达式过滤 Django 查询集?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM