对Sum进行注释会导致None而不是零

时间:2011-05-28 09:01:46

标签: django django-models django-orm

我正在创建一个类似于您当前所在页面的质量检查网站。我试图通过他们的分数来命令答案,但是没有选票的答案将他们的分数设置为无而不是0.这导致答案没有选票在页面底部排在负排名的答案之下。如果没有答案投票,我怎样才能使注释得分为零?

这是我的模特:

from django.contrib.auth.models import User

Answer(models.Model):
    //some fields here
    pass

VOTE_CHOICES = ((-1, Down), (1, Up))

Vote(models.Model):
    user = models.ForeignKey(User)
    answer = models.ForeignKey(Answer)
    type = models.IntegerField(choices = VOTE_CHOICES)

    class Meta:
        unique_together = (user, answer)

这是我的疑问:

answers = Answer.objects.filter(<something here>)
                        .annotate(score=Sum('vote__type'))
                        .order_by('-score')

编辑:要清楚,我想在查询中执行此操作。我知道我可以把它变成一个列表,然后在我的python代码中对它进行排序,但如果可能的话,我想避免这样做。

3 个答案:

答案 0 :(得分:95)

您可以使用django.db.models.functions中的Coalesce function赞:

answers = Answer.objects.filter(<something here>)
                        .annotate(score=Coalesce(Sum('vote__type'), 0))
                        .order_by('-score')

答案 1 :(得分:4)

您可以使用此解决方法,但我不确定它与不同数据库的兼容性(但在sqlite3中工作):

Answer.objects.extra(select={
     'score': 'IFNULL((SELECT SUM(type) ' + \
                       'FROM <yourapp>_vote ' + \
                       'WHERE <yourapp>_vote.answer_id = ' + \
                             '<yourapp>_answer.id), ' + \
                      '0)'
}).order_by('-score')

答案 2 :(得分:-2)

您使用自定义Manager怎么样?例如:

AnswerManager(models.Manager):
    def all_with_score(self):
       qs = self.get_query_set().annotate(score=Sum('vote__type'))
       # Here, you can do stuff with QuerySet, for example
       # iterate over all Answers and set 'score' to zero if None.

Answer(models.Model):
    //some fields here
    objects = AnswerManager()

然后,您可以使用:

>>> answers = Answer.objects.all_with_score().order_by('-score')