繁体   English   中英

Django queryset - 在 annotate(F()) 之后添加 HAVING 约束

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

视觉的

  • pack_1 (A, B) 状态正常
  • pack_2 (B, C) 状态不正常
  • pack_3 (B, D) 状态正常
  • pack_4 (D) 状态不正常

我的任务是 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM