【问题标题】:django annotate models with an aggregate value based on querydjango 使用基于查询的聚合值注释模型
【发布时间】:2018-02-24 23:30:40
【问题描述】:

假设我有以下模型结构:

Parent():

Child():
parent = ForeignKey(Parent)

GrandChild():
child = ForeignKey(Child)
state = BooleanField()
num = FloatField()

我正在尝试从父 ViewSet 恢复以下内容:

  1. 孩子的数量。
  2. 当 'state' 为 True 时,'num' 字段的 SUM。

我可以做到以下几点:

queryset = Parent.objects\
    .annotate(child_count=Count('child'))\
    .annotate(sum_total=Sum('child__grandchild__num'))

这给了我 (1) 但不是 (2) 它给了我所有孙子的总和。如何在确保所有 Parent 对象仍在 QuerySet 中的同时适当地过滤孙子对象?

【问题讨论】:

    标签: django django-models django-queryset django-aggregation django-annotate


    【解决方案1】:

    您使用的是哪个版本的 django?如果版本受支持,您也可以使用子查询。

    from django.db.models import OuterRef, Subquery
    
    Parent.objects
    .annotate(child_count=Count('child'))
    .annotate(
        grandchild_count_for_state_true=Subquery(
            GrandChild.objects.filter(
                state=True,
                child=OuterRef('pk')
            ).values('parent')
            .annotate(cnt=Sum('child__grandchild__num'))
            .values('cnt'),
            num=models.IntegerField()
        )
    )
    

    您可以通过聚合查询对此进行优化。

    【讨论】:

    • 子查询可能是我需要遵循的路线,但您的答案不正确。 1. 我在寻找总和,而不是计数。 2. 我没有名为“事件”的模型。 3. 字段 'num' 是 Fl​​oatField,而不是 IntegerField。
    【解决方案2】:

    尝试在注释前使用过滤器

    queryset = Parent.objects.filter(child__grandchild__state='True')\
        .annotate(child_count=Count('child'))\
        .annotate(sum_total=Sum('child__grandchild__num'))
    

    【讨论】:

    • 这可行,但我需要确保我拥有所有 Parent 对象。抱歉,我将编辑最初的问题。
    • @Eric 您将从这里获取父对象查询集。
    • 如果特定的 Parent 没有 GrandChild 怎么办?
    • 这将只选择孙子状态为 True 的那些对象,因此如果没有孙子,则它不会包含在查询集中 @Eric
    • 你知道annotate是用来对数据进行分组的。它将输出一个类似 dict 的对象,其中每个对象至少有一个来自父对象的 pk 参数。您可以使用该参数通过迭代整个输出来从数据库中获取父对象
    【解决方案3】:

    您可以执行以下操作:

    qs = Parents.objects.all()
    child_count = Count('children')
    num_sum = Sum('children__grandchildren__num', filter=Q(children__grandchildren__state=True))
    qs = qs.annotate(child_count=child_count).annotate(num_sum=num_sum)
    

    chidlren 和 grandchildren 是您可以在模型中定义的相关名称

    【讨论】:

      猜你喜欢
      • 2020-05-23
      • 1970-01-01
      • 2017-07-21
      • 2019-08-03
      • 2023-03-29
      • 2021-04-08
      • 1970-01-01
      • 2015-12-29
      • 2018-06-15
      相关资源
      最近更新 更多