Django 查询(聚合和计数)

发布于 2024-11-09 15:45:26 字数 1485 浏览 8 评论 0原文

嘿伙计们,我有一个如下所示的模型:

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 的计数。很明显,从代码来看它是这样工作的,但想知道如何修复它......

Hey guys, I've got a model that looks like this:

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)

I want to be able to do one query to get the count of the interactions grouped by container then by kind. The idea being that the output JSON data structure (serialization taken care of by piston) would look like this:

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

The SQL would look like this:

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

Any ideas on how to group by multiple fields using the ORM? (I don't want to write raw queries for this project if I can avoid id) This seems like a simple and common query.

Before you ask: I have seen the django aggregates documentation and the raw queries documentation.

Update
As per advice below I've created a custom manager to handle this:

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)

This only counts the interactions that are of kind tag or com instead of retrieving the counts of tags and of the coms via group by. It is obvious that it works that way from the code but wondering how to fix it...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

妄断弥空 2024-11-16 15:45:26

创建自定义管理器:

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

更新

因此,在更好地了解您的模型之后,注释将不再适用于您正在寻找的内容。事实上,唯一获得有多少Container拥有'tag'或'com'kind的方法是:

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

注释不会给你这些信息。我认为可以编写自己的聚合和注释,因此这可能是一个可能的解决方案。然而,我自己从来没有这样做过,所以我不能给你任何指导。您可能一直坚持使用直接 SQL。

Create a custom manager:

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()

Then, Container queries will always include tag_count and com_count attributes. You'll probably need to modify the annotations, since I don't have a copy of your model to refer to; I just guessed on the field names.

UPDATE:

So after gaining a better understanding of your models, annotations won't work for what you're looking for. Really the only to get counts for how many Containers have kinds of 'tag' or 'com' is:

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

Annotations won't give you that information. I think it's possible to write your own aggregates and annotations, so that might be a possible solution. However, I've never done that myself, so I can't really give you any guidance there. You're probably stuck with using straight SQL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文