Django查询以求和ArrayFields的长度

时间:2017-07-19 04:05:53

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

我有这个型号:

class Interaction(models.Model):
    user = models.ForeignKey(User)
    codes = ArrayField(models.CharField(choices=CODE_CHOICES))

我正在试图弄清楚如何在Django中执行相当于这个SQL查询:

select user_id, sum(cardinality(codes)) from interaction group by user_id;
  • 我试过了extra(select={codes_len':'cardinality(codes)'}),但是你 在annotate字段上无法aggregateextra
  • 我试过了annotate(Sum("cardinality('codes')")),但是 cardinality('codes')不是模型上的字段。
  • 我调查过编写一个合并Sum的自定义聚合字段 和cardinality,但看起来......脆弱。
  • 我在文档中发现__len可以正常运行 ArrayField,但不是在上下文中 annotate(Sum('codes__len'))
  • 我排除了原始SQL,因为有很多WHERE语句(这里省略),这使得这个查询难以手工重构。

此时我认为我别无选择,只能在模型中添加一个字段,该字段是codes字段的长度,并与save()混乱以保持同步。

真的没有别的办法吗?我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

事实证明,自定义聚合函数是可行的方法!

以下内容:

from django.db.models import Aggregate

class SumCardinality(Aggregate):
    template = 'SUM(CARDINALITY(%(expressions)s))'

查询非常简单:

Interaction.objects().filter(xxx).\
    values('user_id').annotate(codes_len=SumCardinality('codes'))