django - 在Django ORM中过滤聚合

标签 django django-models aggregate

我有一个看起来像这样的函数:

def post_count(self):
        return self.thread_set.aggregate(num_posts=Count('post'))['num_posts']

我只想统计其状态标记为“事件”的帖子。有没有一种简单的方法可以在Count函数之前添加过滤器?

型号定义:
class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=100, blank=True, primary_key=True)
    ordering = models.IntegerField(max_length=3, default=0)

    @property
    def thread_count(self):
        return self.thread_set.all().count()

    @property
    def post_count(self):
        return self.thread_set.aggregate(num_posts=Count('post'))['num_posts']

class Thread(models.Model):
    user = models.ForeignKey(User)
    category = models.ForeignKey(Category)
    title = models.CharField(max_length=100)
    slug = models.SlugField(max_length=100)
    content = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    latest_activity = models.DateTimeField(auto_now_add=True)

class Post(models.Model):
    thread = models.ForeignKey(Thread)
    parent = models.ForeignKey('Post', null=True, blank=True)
    display_name = models.CharField(max_length=100)
    email = models.EmailField(db_index=True)
    ip_address = models.IPAddressField(null=True, blank=True)
    content = models.TextField()
    status = models.CharField(choices=STATUS_CHOICES, max_length=25, db_index=True, default='approved')
    created = models.DateTimeField()

最佳答案

好的,现在该问题包括模型定义,我向您建议这应该起作用,除非您的Django版本不支持我在此处使用的某些功能(在这种情况下,请告诉我!):

Post.objects.filter(thread__in=thread_set, status='active').aggregate(num_posts=Count('id'))

Django允许__in过滤器采用QuerySet来确定sql中的IN子句应该是什么样的,因此,如果您传递thread__in=thread_set,Django将过滤帖子,以便仅那些thread字段指向您线程中的id之一的帖子。保留thread_set以便aggregate调用查看。

这应该只用过滤帖子,而只在其中一个数据库查询中使用类似WHERE thread_id IN ...的内容,而不是在每个线程中使用一个查询,这确实很糟糕。如果发生任何其他情况,这将是Django中的错误...

结果最多应为,最多两个查询以建立Category的后计数 -一个用于获取thread_set的查询,另一个用于实际计数的职位。另一种方法是根据Threadcategory字段和Poststatus字段来过滤线程/帖子联接,我并不一定希望这样做会更快。 (我说“最多”,是因为我猜它们可能会自动融合...尽管我不认为当前的Django会发生这种情况。抱歉,无法检查ATM。)

编辑: Django's QuerySet API reference__in过滤器上这样说:

IN



在给定列表中。

例子:
Entry.objects.filter(id__in=[1, 3, 4])

SQL等效项:
SELECT ... WHERE id IN (1, 3, 4);

您还可以使用查询集动态评估值列表,而不是提供文字值列表:
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

该查询集将被评估为subselect语句:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

上面的代码片段也可以编写如下:
inner_q = Blog.objects.filter(name__contains='Cheddar').values('pk').query
entries = Entry.objects.filter(blog__in=inner_q)

在Django 1.1中已更改:在Django 1.0中,仅后者的代码有效。

第二种形式具有较低的可读性和编写性,因为它访问内部查询属性并需要ValuesQuerySet。如果您的代码不需要与Django 1.0兼容,请使用第一种形式,直接传递查询集。

因此,我猜想Django能够将单个查询 传递给db,以解决此处的问题。如果数据库的查询分析器做得很好,则效果可能几乎是最佳的。 :-)

关于django - 在Django ORM中过滤聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1889176/

相关文章:

django - 在 Django 中记录 Web 服务请求

Django 模型引用像循环?

python - (Django) DetailView 模板不显示信息

sql - 在一个查询中计算 MySQL 中的多行

caching - 我可以在 JMeter 聚合报告中包含带有缓存响应的请求吗

python - Django ORM : Ordering w/aggregate functions — None special treatment

python - Django 重复输入键

python - 使用虚拟环境会影响 Web 应用程序的性能吗?

django - modelform 失败 is_valid w/o setting form.errors

django-tables2 - 访问表类中其他列的值