Django Q过滤器,无法在单个查询中获得结果
Posted
技术标签:
【中文标题】Django Q过滤器,无法在单个查询中获得结果【英文标题】:Django Q filter, cant get results in a single query 【发布时间】:2021-06-10 07:44:16 【问题描述】:我想使用多个条件进行查询以从我的 Order 模型中获取一些对象,但我找不到在单个查询中获取所有结果的方法。除了进行 2 个查询的选项外,我想知道这是否可以只用一个查询,这样我就可以创建一个包含所有这些订单的 CSV 表(这部分已经有效,所以我会坚持查询)。 条件:
支付方式:Paypal 和 Mollie created_at:在 15:00 和 16:00 小时内
&
支付方式:ApplePay created_at:在 17:00 和 18:00 小时内
两个查询:
Order.objects.all() \
.filter(Q(paymethod="Paypal") |
Q(paymethod="Mollie") &
Q(created_at__hour__in=(15, 16)))
Order.objects.all() \
.filter(Q(paymethod="ApplePay")
Q(created_at__hour__in=(17, 18)))
这两个查询单独工作正常,但我想知道是否可以将它们组合成一个查询。
我尝试过类似的方法:
Order.objects.all() \
.filter(Q(paymethod="Paypal" | "Mollie", created_at__hour__in=(15, 16)) \
& Q(paymethod="ApplePay", created_at__hour__in=(17, 18)))
上述方法不起作用,因为:类型错误:|: 'str' 和 'str' 的操作数类型不受支持。
所以我尝试了 paymethod="Paypal" | "Mollie"
而不是 paymethod="Paypal" | paymethod="Mollie"
但不幸的是,这也不起作用..
如果有人能指出我正确的方向,我将不胜感激。我还在学习 django,django Q 对我来说是新的。如果需要任何其他信息,请告诉我!谢谢!
【问题讨论】:
您显示的第一个查询已经走在正确的轨道上。为什么不像在第一个查询中那样在 Q 对象上简单地使用|
和 &
?如果这是运算符优先级的问题,请尝试使用括号。
感谢您的评论。我知道我在第一次查询时很接近,但它无法解决。 (可能是因为睡眠不足..)但是由于下面的答案,它现在可以工作了!
【参考方案1】:
我认为您根本不需要使用Q
。这个用例应该被QuerySet.filter
和Queryset.union
覆盖。
Order.objects.filter(
paymethod__in=["Paypal", "Mollie"],
created_at__hour__in=[15, 16],
).union(
Order.objects.filter(
paymethod="ApplePay",
created_at__hour__in=[17, 18],
)
)
当您将多个参数传递给filter
时,django 将在生成的 sql 语句中使用 sql AND
。这相当于将您的 Q
对象与集合交集运算符 &
连接起来。
QuerySet.union 方法等价于查询集上的|
运算符
并将转换为 sql UNION
。 (Q 对象上的 |
运算符将转换为 sql OR
操作。)
接受param__in=[...]
的Django 查询集方法会将这些参数转换为sql IN 语句。这应该等同于使用Q | Q
(给出相同的结果)。
filter(paymethod__in=["Paypal", "Mollie"])
# produces same results as
filter(Q(paymethod="Paypal") | Q(paymethod="Mollie"))
我怀疑在典型情况下 IN 会更快,但您应该有基准来确认这一点。
【讨论】:
union
没有使用 SQL OR
,它实际上使用了 SQL UNION
运算符。
@AbdulAzizBarkat:你是对的。谢谢指正。
非常感谢先生!我现在可以使用Queryset.union
:)【参考方案2】:
您可以进一步嵌套子查询,如下所示:
Order.objects.filter(
Q(
Q(paymethod="Paypal") |
Q(paymethod="Mollie") &
Q(created_at__hour__in=(15, 16))
) |
Q(
Q(paymethod="ApplePay")
Q(created_at__hour__in=(17, 18))
)
)
更新: 此外,如果您出于某种原因不想使用“Q”对象,您可以“合并”查询集:
q1 = Order.objects.all() \
.filter(Q(paymethod="Paypal") |
Q(paymethod="Mollie") &
Q(created_at__hour__in=(15, 16)))
q2 = Order.objects.all() \
.filter(Q(paymethod="ApplePay")
Q(created_at__hour__in=(17, 18)))
result = q1 | q2
【讨论】:
【参考方案3】:您可以使用嵌套的 Q 对象来做到这一点,如下所示:
Order.objects.filter(
Q(
Q(paymethod="Paypal") | Q(paymethod="Mollie") & Q(created_at__hour__in=(15, 16))
) |
Q(
Q(paymethod="ApplePay") & Q(created_at__hour__in=(17, 18))
)
)
【讨论】:
以上是关于Django Q过滤器,无法在单个查询中获得结果的主要内容,如果未能解决你的问题,请参考以下文章