До введения аннотаций вы могли бы использовать extra
, чтобы сделать что-то подобное, что я думаю, должно вернуть 0
в случаях, когда нет голосов (если это не относится к какой-либо конкретной реализации базы данных, вы можете по крайней мере напрямую вставить необходимый COALESCE
вызов функции - COALESCE(SUM(value), 0)
- используя этот метод):
pictures = gallery.picture_set.extra(
select={
'score': 'SELECT SUM(value) FROM yourapp_picturevote WHERE yourapp_picturevote.picture_id = yourapp_picture.id',
},
order_by=['-score']
)
Я не вижу никакого встроенного способа добавить свой собственный SQL к новому аннотационному материалу (который я лично пока не использовал), но похоже, что вы должны быть в состоянии создать новую аннотацию следующим образом:
from django.db.models import aggregates
from django.db.models.sql import aggregates as sql_aggregates
class SumWithDefault(aggregates.Aggregate):
name = 'SumWithDefault'
class SQLSumWithDefault(sql_aggregates.Sum):
sql_template = 'COALESCE(%(function)s(%(field)s), %(default)s)'
setattr(sql_aggregates, 'SumWithDefault', SQLSumWithDefault)
Это выглядит довольно некрасиво, так как вам нужно monkeypatch новый агрегат в django.db.models.sql.aggregates
из-за способа поиска классов агрегатов SQL, но все, что мы здесь сделали, добавили новый агрегат, который подклассов Sum
, жесткое кодирование вызов функции COALESCE
и добавление заполнителя для значения по умолчанию, которое вы должны предоставить в качестве аргумента ключевого слова (по крайней мере, в этом базовом примере реализации).
Это должно позволить вам сделать следующее:
pictures = gallery.picture_set.annotate(score=SumWithDefault('picturevote__value', default=0).order_by('-score')