【问题标题】:Django queryset - Add HAVING constraint after annotate(F())Django 查询集 - 在 annotate(F()) 之后添加 HAVING 约束
【发布时间】:2022-02-05 22:03:09
【问题描述】:

在查询中添加 HAVING 时,我遇到了一种看似正常的情况。 我读了herehere,但对我没有帮助

我需要将 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_Packages:

|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) 状态不正常

我的任务是选择那些 latest 包裹状态 = 1

的产品

预期结果是: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.查询

选择 "product"."id", MAX("product_packages"."package_id") AS "pack_id"
FROM "product" 左外连接 "product_packages" ON ("product"."id" = "product_packages"."product_id") 左外连接 "package" ON ("product_packages"."package_id" = "package"."id ")
WHERE "package"."status" = 1
按“产品”分组。“id”

请帮我制作正确的 ORM

【问题讨论】:

    标签: python django filter orm


    【解决方案1】:

    删除后查询的样子

    .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')
    

    会产生不同的查询

    【讨论】:

      【解决方案2】:

      Haki Benita 有一个非常棒的网站,专为 Database Gurus 以及如何制作大部分 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')
      )
      

      或者类似的东西,我还没有测试过这个

      【讨论】:

        【解决方案3】:

        我想你可以试试subquery

        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 模型并按Package 的主键对它们进行排序来准备子查询。然后我从子查询中取出最新的值并用Product查询集注释它,并用1过滤掉状态。

        【讨论】:

          猜你喜欢
          • 2015-10-17
          • 2013-10-24
          • 2019-02-15
          • 2020-08-21
          • 1970-01-01
          • 1970-01-01
          • 2019-06-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多