Django: подсчитывать только непустые CharField с помощью annotate() и values()

Django рекомендует не использовать null для CharField, однако аннотация содержит пустые строки в счете. Есть ли способ избежать этого, не исключая строки с пустой строкой из запроса?

Мой вопрос заключается не просто в том, как выполнить мой запрос, а в том, должен ли счетчик аннотаций/объединений включать пустые поля или нет. Django считает пустым заменой NULL для строковых полей.

Моя модель:

class Book(models.Model):
    name = models.CharField(...)

class Review(models.Model):
    book = models.ForeignKey()
    category = models.ForeignKey()
    review = models.CharField(max_length=200, default='', blank=True)

Чтобы подсчитать непустые отзывы и сгруппировать по категориям, я использую

Review.objects.values('category').annotate(count=Count('review'))

Это не работает, потому что annotate также подсчитывает пустые значения (если бы запись была NULL, этого бы не произошло). Я мог бы отфильтровать пустые строки перед вызовом аннотации, но мой запрос более сложный, и мне нужны все пустые и непустые объекты.

Есть ли более разумный способ использовать аннотировать и пропускать пустые значения из подсчета или мне следует изменить модель с

review = models.CharField(max_length=200, default='', blank=True)

to

review = models.CharField(max_length=200, default=None, blank=True, null=True)

person user    schedule 25.05.2014    source источник
comment
Из описания вопроса: I could filter out empty strings before the annotate call but my Query is more complex and I need all empty & non-empty objects   -  person user    schedule 25.05.2014
comment
Боюсь, добавление null=True вам не поможет. Вы должны использовать необработанный SQL-запрос docs.djangoproject.com/en/dev/topics /дб/sql   -  person Sławek Kabik    schedule 25.05.2014
comment
можете ли вы использовать метод order_by, за которым следует отдельный? Однако проверьте документы django, они предупреждают о таком случае: docs .djangoproject.com/en/dev/ref/models/querysets/#distinct   -  person vlad-ardelean    schedule 25.05.2014


Ответы (2)


Я столкнулся с очень похожей ситуацией. Я решил это с помощью условных выражений:

review_count = Case(
    When(review='', then=0),
    default=1,
    output_field=IntegerField(),
)
Review.objects.values('category').annotate(count=review_count)
person Mauricio    schedule 12.02.2021

... и мне нужны все пустые и непустые объекты.

Это не имеет никакого смысла при использовании values. Вместо реальных объектов вы получите список словарей, содержащих только ключи category и count. Помимо другого числа в count, вы не увидите никакой разницы между фильтрацией пустых значений review или нет. Кроме того, вы фильтруете одну книгу (id=2) и каким-то образом ожидаете, что отзывов может быть больше одного.

Вам нужно серьезно переосмыслить, что именно вы пытаетесь сделать, и как определение вашей модели вписывается в это.

person knbk    schedule 25.05.2014
comment
В запросе будут другие вычисления (среднее/макс./минимальное) для других полей модели. Эти поля не зависят от review. Я хочу добиться этого в одном запросе. Я написал упрощенную модель, чтобы сосредоточиться на том, что я просил. Добавлено больше деталей в модель, чтобы ответить на некоторые ваши вопросы. - person user; 25.05.2014