【问题标题】:django complex queryset annotationdjango 复杂查询集注解
【发布时间】:2013-04-25 16:03:27
【问题描述】:

我想将在每个用户的页面请求中计算的一些统计数据添加到查询集中,以显示在一个大表中。 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() 聚合函数不接受过滤器。

【问题讨论】:

    标签: django django-queryset


    【解决方案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()
    

    这也可以使用信号来实现。

    【讨论】:

    • 我正在考虑像这样使用数据库,但希望避免这种情况。无论如何这是最合理的解决方案。
    【解决方案2】:

    您始终可以在 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/,了解执行重要查询集注释的相关场景。

    【讨论】:

      猜你喜欢
      • 2013-03-19
      • 2014-12-22
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 2011-06-08
      相关资源
      最近更新 更多