Django查询(聚合和计数)

时间:2011-05-24 20:35:58

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

嘿伙计们,我有一个看起来像这样的模型:

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)

这只计算kind标签或com的交互,而不是通过group by检索标签和com的计数。很明显,它从代码中运行,但想知道如何修复它......

1 个答案:

答案 0 :(得分:2)

创建自定义管理器:

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个属性。您可能需要修改注释,因为我没有要引用的模型副本;我只是猜到了字段名称。

<强>更新

因此,在更好地了解您的模型之后,注释将无法满足您的需求。真的唯一可以计算Containerkind个'tag'或'com'的数量是:

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

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