Проблема с выполнением подсчета методом группировки с использованием аннотированного поля
Context
У меня есть таблица/модель под названием Article.
В этой модели у меня есть несколько полей, таких как срок действия, видимость и статус. Эти поля определяют, должна ли статья отображаться или нет. По сути, желаемая логика выглядит следующим образом:
display = True
if status == 'Private'; display = False
if visibility == False; display = False
...
Для простоты в этом посте я буду использовать только одно поле: status
. Поле status
представляет собой CharField
с вариантами выбора: 'Private'
или 'Public'
.
Для того чтобы разработать логику отображения, я использую аннотацию. Это относительно просто:
all_articles = Article.objects.annotate(
display=Case(When(status='Private', then=Value(False)), default=Value(True), output_field=models.BooleanField())
)
displayed_articles = all_articles.filter(display=True)
notdisplayed_articles = all_articles.filter(display=False)
Гол
При такой настройке я хотел бы использовать Django ORM для выполнения подсчета с группировкой по, чтобы определить, сколько статей отображается, а сколько нет.
В табличном формате SQL результат будет выглядеть следующим образом:
display | count |
---|---|
True | 500 |
False | 2000 |
Проблема
Это естественный способ достижения моей цели:
queryset = Article.objects.annotate(
display=Case(
When(status='Private', then=Value(False)), default=Value(True), output_field=models.BooleanField()
)
).values('display').annotate(count=Count('id')).order_by()
print(queryset)
Ожидание
Я ожидаю что-то вроде этого:
<QuerySet [{'display': True, 'count': 500}, {'display': False, 'count': 2000}]>
Ошибка
Однако я получаю следующее:
django.db.utils.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'blog_article.status' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. (8120) (SQLExecDirectW)")
Почему это происходит и как я могу это обойти?
Исследование SQL-запроса
Я изучил сгенерированный SQL-запрос следующим образом:
print(queryset.query)
SELECT CASE
WHEN [blog_article].[status] = Private THEN False
ELSE True
END AS [display],
COUNT_BIG([blog_article].[id]) AS [count]
FROM [blog_article]
GROUP BY CASE
WHEN [blog_article].[status] = Private THEN False
ELSE True
END
Общая структура запроса выглядит нормально, мне нужно было лишь внести в него небольшие изменения. Приведенный ниже запрос был успешно выполнен по отношению к базе данных.
SELECT CASE
WHEN [blog_article].[status] = "Private" THEN 1
ELSE True
END AS [display],
COUNT_BIG([blog_article].[id]) AS [count]
FROM [blog_article]
GROUP BY CASE
WHEN [blog_article].[status] = "Private" THEN 0
ELSE True
END
Я также проверил выполнение этого запроса, используя pyodbc
, и он был выполнен успешно.