【问题标题】:Django Query (aggregates and counts)Django 查询(聚合和计数)
【发布时间】:2011-09-01 06:32:42
【问题描述】:

大家好,我有一个看起来像这样的模型:

class Interaction(DateAwareModel, UserAwareModel):
  page = models.ForeignKey(Page)
  container = models.ForeignKey(Container, blank=True, null=True)
  content = models.ForeignKey(Content)
  interaction_node = models.ForeignKey(InteractionNode)
  kind = models.CharField(max_length=3, choices=INTERACTION_TYPES)

我希望能够进行一次查询以获取按容器分组的交互计数,然后按种类分组。输出 JSON 数据结构(由活塞负责序列化)的想法如下所示:

"data": {
   "container 1": {
       "tag_count": 3, 
       "com_count": 1
   },
   "container 2": {
       "tag_count": 7, 
       "com_count": 12
   },
   ...
}

SQL 将如下所示:

SELECT container_id, kind, count(*) FROM rb_interaction GROUP BY container_id, kind;

关于如何使用 ORM 按多个字段分组的任何想法? (如果可以避免 id,我不想为这个项目编写原始查询)这似乎是一个简单而常见的查询。

在你问之前:我已经看过 django 聚合文档和原始查询文档。

更新 根据以下建议,我创建了一个自定义管理器来处理此问题:

class ContainerManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(ContainerManager, self).get_query_set(*args, **kwargs)
        qs.filter(Q(interaction__kind='tag') | Q(interaction__kind='com')).distinct()
        annotations = {
            'tag_count':models.Count('interaction__kind'),
            'com_count':models.Count('interaction__kind')
        }
        return qs.annotate(**annotations)

这仅计算类型标签或 com 的交互,而不是通过 group by 检索标签和 com 的计数。很明显,它从代码中以这种方式工作,但想知道如何修复它......

【问题讨论】:

    标签: django django-models django-orm django-piston


    【解决方案1】:

    创建自定义管理器:

    class ContainerManager(models.Manager):
        def get_query_set(self, *args, **kwargs):
            qs = super(ContainerManager, self).get_query_set(*args, **kwargs)
            annotations = {'tag_count':models.Count('tag'), 'com_count':models.Count('com')}
            return qs.annotate(**annotations)
    
    class Container(models.Model):
        ...
        objects = ContainerManager()
    

    然后,Container 查询将始终包含 tag_countcom_count 属性。您可能需要修改注释,因为我没有您的模型副本可供参考;我只是猜到了字段名。

    更新:

    因此,在更好地了解您的模型之后,注释将无法满足您的需求。真正了解有多少Containers 有kinds 的'tag'或'com'的唯一方法是:

    tag_count = Container.objects.filter(kind='tag').count()
    com_count = Container.objects.filter(kind='com').count()
    

    注释不会为您提供这些信息。我认为可以编写自己的聚合和注释,所以这可能是一个可能的解决方案。但是,我自己从来没有这样做过,所以我不能在那里给你任何指导。您可能无法使用直接的 SQL。

    【讨论】:

    • 出色的响应,但我主要担心的是:我希望能够在数据库中进行聚合工作,而不是遍历容器。我可能错了,但似乎这会计算每个容器的标签和 cmets(隐含循环),而使用 group by 子句可以更好地利用数据库引擎。想法?
    • 没有迭代。 annotatefilter 和查询集 API 的其余部分类似。它只是将东西附加到将发送到数据库的最终 SQL 上。只有一个查询。
    • Kind 实际上在我的交互模型中,如果我想在 'interaction__kind' = 'tag' 或 'com' 处注释计数,你介意提一下你会怎么做吗?
    • 只需在.annotate 之前插入.filter(Q(interaction__kind='tag') | Q(interaction__kind='com')).distinct()Qdjango.db.models 中。
    • 是的,根据您的更新,它不起作用。我基于 tagcom 是“可数”的东西(即外键)的假设编写了答案。我会在上面更新我的答案,但你可能不会喜欢它;)。
    猜你喜欢
    • 1970-01-01
    • 2023-03-19
    • 2012-04-01
    • 1970-01-01
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-05
    相关资源
    最近更新 更多