【问题标题】:Spanning relationship to obtain field value with .annotate() and .values() clauses使用 .annotate() 和 .values() 子句跨越关系以获取字段值
【发布时间】:2022-01-13 15:30:27
【问题描述】:

我正在对查询集使用值和注释进行一些计算。让我们考虑这个模型:

class Foo(models.Model):
   fk_bar = models.ForeignKey(to=Bar, ....)
   foo_val = models.IntegerField(...)

class Bar(models.Model):
   attr = models.Charfield(...)
   val  = models.IntegerField(...)

所以我可以这样做:

Foo.object.all().values("fk_bar")

为了按外来关系分组(某些 Foo 可能指向同一个 Bar)。

那我就可以了

Foo.object.all().values("fk_bar").annotate(qte=Sum("foo_val"))

对于具有相同 fk_bar 的所有对象的 foo_val 的总和,产生类似的结果:

{"fk_bar":<int>, "qte": <int>}

但是我希望生成的字典也包含 Bar.attr,例如类似:

Foo.object.all().values("fk_bar").annotate(qte=Sum("foo_val")).annotate(bar_attr="fk_bar__attr")

得到类似的东西:

{"fk_bar":<int>, "qte": <int>, "bar_attr":<str>}

但是失败了(TypeError: Queryset.annotate() 收到了一个非表达式)。有什么办法可以解决这个问题?

【问题讨论】:

    标签: django annotations django-queryset


    【解决方案1】:

    一种选择是在 values() 子句中从聚合之前指定要“保留”的附加值,如下所示:

    Foo.object.all().values("fk_bar", "fk_bar__attr").annotate(qte=Sum("foo_val"))
    

    这将大致产生所要求的内容。

    一般来说,如果在.values() 子句中放置更多字段,则这些字段将在输出字典中可用。任何需要预先计算(例如聚合之前)的“附加”字段(例如,不是来自原始查询集数据)都可以使用.annotation()(如上面的qte=Sum(...))“创建”,然后包含在后续的@987654325 中@。几个例子:

    得出所有具有相同 fk_bar 的 Foo 的总和:

    Foo.object.all().values("fk_bar").annotate(qte=Sum("foo_val"))
    

    这将按 fk_bar 和 foo_val 对所有 Foo 进行分组。然后对每一组,将 fk_bar__val 字段的值相加:

    Foo.object.all().values("fk_bar", "foo_val").annotate(qte=Sum("fk_bar__val"))
    

    需要注意的是,如果.values() 中指定了许多字段,那么聚合将更大(例如,每个唯一的值组合对应一个字典)。

    【讨论】:

      猜你喜欢
      • 2016-10-19
      • 2021-11-13
      • 1970-01-01
      • 1970-01-01
      • 2014-12-29
      • 2019-04-06
      • 2020-08-28
      • 1970-01-01
      • 2015-10-17
      相关资源
      最近更新 更多