【问题标题】:How can I filter a Django queryset using just a CASE or a COALESCE expression?如何仅使用 CASE 或 COALESCE 表达式过滤 Django 查询集?
【发布时间】:2018-01-15 20:13:19
【问题描述】:

我将 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。

【问题讨论】:

    标签: python django postgresql


    【解决方案1】:

    这是我自己想出来的。由于尚未发布真正的答案,这是我的解决方案:

            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 会导致与原始查询相同的结果,但我仍然希望使用不太冗长的代码。

    在那之前,我会将我的问题标记为已回答。

    【讨论】:

      【解决方案2】:

      我相信 Q() 的结果总是 True 或 False,所以在 Coalesce 表达式中使用它是行不通的。解决方案是使用条件表达式,结合 Case 和 filter。 您可以找到您需要的所有信息here 在文档中。

      【讨论】:

        猜你喜欢
        • 2019-08-08
        • 1970-01-01
        • 2016-02-01
        • 2019-08-18
        • 2018-11-15
        • 1970-01-01
        • 2020-08-22
        • 2019-04-15
        相关资源
        最近更新 更多