Аннотирование суммы приводит к None, а не к нулю

Я делаю сайт контроля качества, похожий на страницу, на которой вы сейчас находитесь. Я пытаюсь упорядочить ответы по их баллам, но для ответов, за которые не было голосов, оценка устанавливается на «Нет», а не на 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, но я бы хотел избежать этого, если это возможно.


person Jackie    schedule 28.05.2011    source источник
comment
К вашему сведению, существует открытый тикет Django о значениях по умолчанию для Sum().   -  person Gary    schedule 08.02.2012


Ответы (2)


Вы можете использовать функцию Coalesce из django.db.models.functions, например:

answers = (Answer.objects
    .filter(<something here>)
    .annotate(score=Coalesce(Sum('vote__type'), 0))
    .order_by('-score'))
person nelson orland    schedule 15.02.2016
comment
По иронии судьбы, я думаю, этот ответ находится внизу для меня. - person andho; 14.07.2017
comment
ВАЖНО coalesce возвращает null, если строки не найдены. К сожалению, я должен найти другое решение - person Eugene Kovalev; 04.12.2018
comment
@EugeneKovalev Coalesce возвращает значение по умолчанию, если само запрошенное значение равно null. Он не оценивает целые строки, верно? - person Adam Starrh; 02.04.2019
comment
@EugeneKovalev Вы нашли решение для coalesce возврата null при отсутствии строк? - person Redgren Grumbholdt; 07.10.2020
comment
@kingraphaii нет, я не - person Eugene Kovalev; 08.10.2020
comment
Спасибо за ответ. Мне удалось использовать условные фильтры, чтобы заставить его работать. - person Redgren Grumbholdt; 08.10.2020
comment
@EugeneKovalev Что? Нет. - person ruohola; 08.12.2020
comment
@ruohola мой плохой, я не указал достаточно подробностей в этом комментарии. Это зависит от используемой БД, а не от Django. Я тогда использовал PostgreSQL. - person Eugene Kovalev; 23.12.2020
comment
@EugeneKovalev Есть идеи о PostgreSQL с нулевыми строками? - person Akshay Hazari; 06.01.2021

Как насчет использования пользовательского 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')
person vasco    schedule 28.05.2011
comment
Вопрос заключался в том, как заменить значения None на 0 для встроенной агрегатной функции Sum. Это не так - person Patrick; 15.06.2014