在Django ORM中从外键获取计数的更好方法

时间:2014-07-19 07:41:41

标签: python django django-orm

Django的ORM如何在性能方面处理以下问题,以及解决问题的最佳方法是什么......

我有两个模型ProjectProjectVote。我想在model method上提供一个Projects来显示每个项目在显示时的投票数。

但是我很担心!下面的代码似乎只是一个性能消耗。如果我加载所有项目并在每个项目上调用vote_count方法,我猜我会多次击中数据库然后我需要!有没有更好的办法?感谢

class Project(RewardBase):
    """
    Represents a Project.
    """
    title = models.CharField(max_length=80, help_text="Name of the project")
    description = models.TextField(max_length=500)

    user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True)
    created = models.DateTimeField(blank=True, null=True, editable=False)

    def __unicode__(self):
        return self.title

    def vote_count(self):
        """
        Return the number of votes this project has had.
        """
        return ProjectVote.objects.filter(project=self.project).count()


class ProjectVote(RewardBase):
    """
    Represents a vote for a Project.
    """

    user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True)
    project = models.ForeignKey('Project', related_name="votes")

2 个答案:

答案 0 :(得分:2)

如果您想一次性计算所有项目,请尝试以下查询:

ProjectVote.objects.values("project_id").annotate(count=Count("project_id"))

这应该生成像[{'project_id': 123, 'count': 5}, ...]这样的结果。您可以将其放在自定义Manager方法中,该方法可根据您的需要返回适当的数据结构。

另请注意,您的单个项目vote_count可以简化为self.votes.count()

答案 1 :(得分:2)

您可以使用相关Project的数量为ProjectVote模型添加注释:

from django.db.models import Count

Project.objects.annotate(vote_count=Count('votes'))

这将在每个vote_count模型实例上设置Project属性。这可以与任意数量的过滤器,order_by查询等结合使用。如果您在注释之前过滤了ProjectVote上的属性(例如votes__user=current_user,则只会过滤结果出席投票计数。

这将导致单个查询同时获取所有Project个实例和相关ProjectVote个实例的计数。