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