什么是获取Django中按字段分组的对象计数的有效方法?

时间:2014-08-08 22:21:22

标签: sql django python-2.7

我正在开发一个大型Django应用程序,特别是它发送许多电子邮件,然后收集有关它们的信息。我有两个模型通过第三个模型相互关联:

SendEvent是我成功发送任意数量电子邮件时捕获的模型 - 它会记录一些与问题无关的数据。

SentEmail是中间表。它包含对SendEvent的外键引用,名为sendevent,以及一些其他额外信息。

然后我有一个名为EmailEvents的模型,该模型正在侦听我使用的第三方邮件应用程序中的某些webhook,并存储有关收件人正在对我的电子邮件进行操作的信息。此模型包含对SentEmail对象的外键引用。有几个EmailEvent将与单个SentEmail关联 - 最相关的是发送的'并且'打开' (当发送电子邮件时,生成的事件将被生成并记录在EmailEvents表中,并通过唯一的id字符串与SentEmail相关联。与open事件类似,除了它是在收件人打开电子邮件时生成的,显然)。事件类型作为字符串存储在名为event的字段中。

我尝试编写一个查询,在给定SendEvent的情况下,它将为我提供不同类型的关联EmailEvents的计数。

到目前为止,我已经解决了以下问题(send_event是包含对相关SendEvent的引用的变量):

email_events = EmailEvents.objects.filter(sent_mail__sendevent = sent_event)

我相信这将获取所有正确的EmailEvent对象(与给定SendEvent关联的SentEmails关联的对象)。然后我可以在其末尾添加.count()并获取所有EmailEvent的计数。但是,我真正想要的是将其分解为不同类型的EmailEvent。我可以通过循环遍历QuerySet来手动执行此操作,但我预计EmailEvents表会变得非常大,所以我非常希望让ORM为我做这个提升。我如何按事件分组?

我可以吗

EmailEvents.objects.filter(sent_mail__sendevent = sent_event).annotate(Count('event'))

这是最好的方法吗?这会起作用吗?任何建议都会非常感激 - 我在处理大量数据方面有点新意。

2 个答案:

答案 0 :(得分:0)

我不确定Django ORM是否有一种简单的方法可以满足您的需求,但您始终可以使用原始SQL - https://docs.djangoproject.com/en/1.7/topics/db/sql/

原始SQL将类似于以下内容(我正在猜测您的表将被调用,但查询基本上如下所示):

select count(distinct(e.event)) from EmailEvents as e, SentEvent where EmailEvent.id = SentEvent.id

答案 1 :(得分:0)

这可以通过将objects.values与annotate一起使用来实现。这是一个样本模型+测试。

首先在models.py

class Foo(models.Model):
    action_type = models.CharField(max_length=50)

然后在tests.py

from django.test import TestCase
from django.db.models import Count
from foo.models import Foo

class MyTestCase(TestCase):
    def test_group_query(self):
        options = ('created', 'deleted', 'updated')
        for i in range(32):
            Foo.objects.create(
                action_type=options[i%3]
                )
        results = Foo.objects.values('action_type').annotate(Count('action_type'))
        print results

生成一个包含以下内容的数组

{'action_type__count': 11, 'action_type': u'created'}, 
{'action_type__count': 11, 'action_type': u'deleted'}, 
{'action_type__count': 10, 'action_type': u'updated'}