[英]Django queryset - Add HAVING constraint after annotate(F())
在查询中添加 HAVING 时,我遇到了看似正常的情况。 我在这里和这里阅读,但这对我没有帮助
我需要将 HAVING 添加到我的查询中
楷模:
class Package(models.Model):
status = models.IntegerField()
class Product(models.Model):
title = models.CharField(max_length=10)
packages = models.ManyToManyField(Package)
产品:
|id|title|
| - | - |
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
套餐:
|id|status|
| - | - |
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 4 | 2 |
产品_包装:
|product_id|package_id|
| - | - |
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
| 3 | 2 |
| 2 | 3 |
| 4 | 3 |
| 4 | 4 |
视觉的
我的任务是 select 那些状态为 1 的最新package 的产品
预期结果是:A,B
我的查询是这样的
SELECT prod.title, max(tp.id)
FROM "product" as prod
INNER JOIN "product_packages" as p_p ON (p.id = p_p.product_id)
INNER JOIN "package" as pack ON (pack.id = p_p.package_id)
GROUP BY prod.title
HAVING pack.status = 1
它返回的正是我所需要的
|title|max(pack.id)|
| - | - |
| A | 1 |
| B | 3 |
但是我的 orm 不能正常工作,我这样尝试
p = Product.objects.values('id').annotate(pack_id = Max('packages')).annotate(my_status = F('packages__status')).filter(my_status=1).values('id', 'pack_id')
p.查询
SELECT "产品"."id", MAX("product_packages"."package_id") AS "pack_id"
从“产品”左外连接“product_packages”ON(“product”。“id”=“product_packages”。“product_id”)左外连接“package”ON(“product_packages”。“package_id”=“package”。“id ")
其中“包”。“状态”= 1
按“产品”分组。“id”
请帮我改正 ORM
删除时查询的外观
.values('id', 'pack_id')
在最后?
如果我没记错的话:
p = Product.objects.values('id').annotate(pack_id = Max('packages')).annotate(my_status = F('packages__status')).filter(my_status=1)
和
p = Product.objects.annotate(pack_id = Max('packages')).annotate(my_status = F('packages__status')).filter(my_status=1).values('id')
将产生不同的查询
Haki Benita 有一个很棒的网站,专为数据库专家和如何充分利用 Django 而设计。
你可以看看这个帖子: https://hakibenita.com/django-group-by-sql#how-to-use-having
Django 有一种添加“HAVING”运算符的非常具体的方法,即您的查询集需要结构化,以便您的注释后面跟着一个“值”调用,以挑出您想要分组的列,然后注释 Max 或任何你想要的聚合。
此外,此注释似乎不起作用annotate(my_status = F('packages__status')
您想要将多个状态注释为单个注释。
您可能想尝试使用子查询来注释您想要的方式。
例如
Product.objects.annotate(
latest_pack_id=Subquery(
Package.objects.order_by('-pk').filter(status=1).values('pk')[:1]
)
).filter(
packages__in=F('latest_pack_id')
)
或者类似的东西,我还没有测试过
我想你可以用子查询这样尝试:
from django.db.models import OuterRef, Subquery
sub_query = Package.objects.filter(product=OuterRef('pk')).order_by('-pk')
products = Product.objects.annotate(latest_package_status=Subquery(sub_query.values('status')[0])).filter(latest_package_status=1)
首先,我通过使用Product
的主键过滤Package
model 并按Package
的主键对它们进行排序来准备子查询。 然后我从子查询中获取最新值并用Product
queryset 对其进行注释,并用 1 过滤掉状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.