我基于一个功能良好的postgres查询作为Django查询集的基础,该查询具有以下WHERE条件:
... 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:“合并”对象不可迭代
不幸的是,我需要在数据库级别进行条件过滤。
是否有一种符号或方法允许使用合并表达式进行选择?
我不喜欢使用rawsql或queryset.extra。
发布于 2018-01-15 18:58:35
我自己想出来的。由于还没有发布真正的答案,以下是我的解决方案:
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可以得到与原始查询相同的结果,但我仍然希望代码不那么冗长。
在那之前,我会把我的问题记下来。
发布于 2022-05-30 16:57:34
编写自己的表达式类的代码片段的开头很小,有关完整源代码,请参阅下面的正式文档链接。
注意:并不是所有的数据库都有连接(),我认为这就是为什么这已经不是一个正式的表达式了。也许可以编写一些代码,将其转换为标准情况(.)表达式作为回退,然后对db特定的sql转换使用COALESCE()。我把它留给读者做练习;)
from django.db.models import Expression
class Coalesce(Expression):
template = 'COALESCE( %(expressions)s )'
...
完整代码的正式文档:Django模型-编写您自己的查询表达式
发布于 2018-01-15 14:35:48
我相信Q()的结果总是真或假,所以在合并表达式中使用它是行不通的。解决方案是使用条件表达式,结合大小写和过滤器。您可以在文档中找到所有需要这里的信息。
https://stackoverflow.com/questions/48270038
复制