django复杂的查询集注释

时间:2013-05-01 16:07:11

标签: django django-queryset

我想在查询集中添加一些在每个用户的页面请求中计算的统计数据,以显示在一个大表中。 annotate方法可能是最好的选择,但我坚持将创建的查询集合并到单个方法中,以便在模板中更容易操作。查询集类型首选于排序数据。

以下是我申请的极其简化的原则。不得触摸模板和模型,因为它显然是我想要的结果。在此示例中未按列实现数据排序。

以下是模型:

class Poll(models.Model):
    question = models.CharField(max_length=200, unique=True)

class Vote(models.Model):
    poll = models.ForeignKey(Poll)
    accept = models.BooleanField()
    comment = models.CharField(max_length=200, unique=True)
    censored = models.BooleanField()

以下是观点:

def summaryView(request):
    …
    contexte['poll_list'] = «insert code here»
    …
    return render_to_response('summary.html, contexte)

这是模板:

<table>
  <thead>
    <tr>
      <th>
        Poll question
      </th>
      <th>
        Number of votes
      </th>
      <th>
        Number of uncensored "yes" votes
      </th>
      <th>
        Number of censored votes
      </th>
    </th>
  </thead>
  <tbody>
    {% for poll in poll_list %}
      <tr>
        <td>
          {{ poll.question }}
        </td>
        <td>
          {{ poll.numUncensoredYesVotes }}
        </td>
        <td>
          {{ poll.numCensoredVotes }}
        </td>
      </tr>
    {% endfor %}
  </tbody>
</table>

困难在于创建未经审查的“是”投票注释的数量。 Count()聚合函数不接受过滤器。

2 个答案:

答案 0 :(得分:1)

对于这个要求,我会在Poll模型中添加两​​个字段,它将使更快的sql查询。通常在这些情况下,选择将比插入更频繁。因此,这将为您的项目带来更多性能提升。

from django.db import models


class Poll(models.Model):
    question = models.CharField(max_length=200, unique=True)
    num_censored_votes = models.PositiveIntegerField(default=0)
    num_uncensored_yes_votes = models.PositiveIntegerField(default=0)


class Vote(models.Model):
    poll = models.ForeignKey(Poll)
    accept = models.BooleanField()
    comment = models.CharField(max_length=200, unique=True)
    censored = models.BooleanField()

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        models.Model.save(self, force_insert, force_update, using, update_fields)
        poll = self.poll

        if self.censored:
            poll.num_censored_votes += 1
            poll.save()

        elif self.accept:
            poll.num_uncensored_yes_votes += 1
            poll.save()

这也可以使用信号实现。

答案 1 :(得分:0)

你总是可以在python中使用3个查询(只需手动加入python中的查询集),但是这里有一个查询的方法: 如果您需要注释的Poll QuerySet是由query1生成的,则一个解决方案是

contexte['poll_list'] = Poll.objects.raw(
    ' select A.*, B.numcensoredvotes, C.numuncensoredyesvotes from 
    ( query1 ) A left join (query2) B on A.id = B.poll_id
    left join (query3) C on A.id = C.poll_id' )

其中query2和query3是聚合查询。 您可以通过以下方式访问查询集的查询:

poll_list = Poll.objects.filter(...)
poll_list.query.get_initial_alias()
(query1,q1param) = poll_list.query.sql_with_params()

您也可以为聚合查询(上面的query2和query3)执行此操作,或者只需手动编写它们。

另请参阅http://www.reddit.com/r/django/comments/1dgz97/annotating_a_queryset_with_a_nontrivial_left/以了解执行非平凡的查询集注释的相关场景。