【问题标题】:Django Query Optimization count a related field of a related fieldDjango查询优化计算相关字段的相关字段
【发布时间】:2016-07-18 01:09:43
【问题描述】:

我正在为我的兄弟会编写一个 Django 应用程序来对 rushees 进行投票,我正在尝试优化我的一个查询,该查询计算选票并打印出计数以及来自他们的应用程序的信息。 Django-debug 工具栏告诉我我有很多重复的查询

(为清楚起见,以下代码已被截断和编辑)

models.py

 votechoices = ((1, "Yes"),(2, "No"),(3, "Abstain"))

 class Vote(models.Model):
      brother = models.ForeignKey(Brother)
      rushee = models.ForeignKey(Rushee)
      choice = models.IntegerField(choices=votechoices, default=3)

 class Rushee(models.Model):
      first_name = models.CharField(max_length=40)
      last_name = models.CharField(max_length=40)
      #ETC, ETC

 class Application(models.Model):
      rushee = models.ForeignKey(Rushee)
      address = models.CharField(max_length=200)
      cellphone = models.CharField(max_length=30)
      #ETC, ETC

views.py

def getvotecount(request):

     # get all the applications ( we only vote on people who have an application)
     applicationobjs = Application.objects.select_related('rushee').all()

     # iterate through the applications and count the votes
     for app in applicationobjs.iterator():

     #>>>> This Query below is a seperate query everytime! So that means that If we have 200 rushees there are 200 queries!
          counts = Vote.objects.filter(rushee=app.rushee).values('choice').annotate(count=Count('choice'))

          votesfor = sum([x['count'] for x in counts if x['choice'] == 1])
          votesagainst = sum([x['count'] for x in counts if x['choice'] == 2])

          result = [app.rushee.first_name + ' ' + app.rushee.last_name,
                    app.address, app.cellphone,
                    str(votesfor), str(votesagainst),]

    # Uninteresting stuff below that will group together and return the results

我正在尝试优化由 (>>>>) 标记的视图中的查询,以便我可以返回每个 rushee 的票数,而无需每次都运行单独的查询!

附加信息: sqlite 后端,rushees 比应用程序多得多,我们只对有应用程序的 rushees 投票

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    您可以使用conditional expressions 在一个查询中完成所有操作:

    from django.db.models import Case, IntegerField, Sum, When
    
    rushees = Rushee.objects.annotate(
        votes_for=Sum(
            Case(
                When(vote=1, then=1),
                default=0,
                output_field=IntegerField(),
            )
        ),
        votes_against=Sum(
            Case(
                When(vote=2, then=1),
                default=0,
                output_field=IntegerField(),
            )
        )
    )
    

    结果查询集中的rushees 将有一个votes_forvotes_against 属性,每个属性都有计数。这假设没有记录反对没有申请的rushees 的投票 - 但如果有,那么您可以轻松地将它们过滤掉。

    【讨论】:

    • Count而不是Sum来计数不是更好吗?如果没有行,Count 返回 0,Sum 返回 None。
    • 我不关注...Count 将返回所有行的计数,而不仅仅是vote 的值与所需值匹配的行?
    猜你喜欢
    • 2011-09-25
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    相关资源
    最近更新 更多