Django TypeError: Невозможно отфильтровать по безусловному выражению при фильтрации по внешнему ключу
Я просмотрел несколько похожих вопросов, но не смог уловить логику, и мои манипуляции оказались безуспешными.
У меня есть приложение для форума, его структура «forum->subforum->topic->comments», соответствующие модели для подфорумов, тем и комментариев. Мне необходимо реализовать фильтр на странице каждого подфорума (где отображается список соответствующих тем), с помощью которого я могу настроить поиск/нахождение тем по нескольким условиям.
В частности, мне нужно реализовать пользовательский фильтр, и моя идея заключалась в создании фильтра для пустых тем, то есть для тем только с начальными комментариями и без ответов. В результате отчаянной борьбы я наконец понял, как реализовать обратную связь по внешнему ключу в кверисетах, но теперь я не могу использовать выражение кверисета в качестве фильтра, так как оно возвращает TypeError: Cannot filter against a non-conditional expression.
Вот конкретика:
filters.py:
import django_filters
from django.db.models import Count
from forum.models import Topic
class TopicFilter(django_filters.FilterSet):
date_span = django_filters.DateRangeFilter(field_name='created', label='Период создания')
comments = django_filters.CharFilter(field_name='comment__content', lookup_expr='icontains', label='Комментарии')
subject = django_filters.CharFilter(lookup_expr='icontains', label='Тема обсуждения')
creator = django_filters.CharFilter(field_name='creator__username', lookup_expr='icontains', label='Создатель темы')
is_empty = django_filters.BooleanFilter(method='filter_empty', label='Темы без комментариев')
class Meta:
model = Topic
fields = ['subject', 'creator', 'date_span', 'comments', 'is_empty']
def filter_empty(self, queryset, value):
comment_count_gte_1 = Topic.objects.annotate(comment_count=Count('comments')).filter(comment_count__gte=1)
comment_count_lt_1 = Topic.objects.annotate(comment_count=Count('comments')).filter(comment_count__lt=1)
if value is True:
return queryset.filter(comment_count_lt_1)
elif value is False:
return queryset.filter(comment_count_gte_1)
else:
return queryset
Вышеописанный подход не работает - видимо, нельзя указать в качестве критерия фильтра ссылку на выражение queryset. Но даже если ввести само выражение, то есть:
def filter_empty(self, queryset, value):
if value is True:
return queryset.filter(Topic.objects.annotate(comment_count=Count('comments')).filter(comment_count__lt=1))
elif value is False:
return queryset.filter(Topic.objects.annotate(comment_count=Count('comments')).filter(comment_count__gte=1))
else:
return queryset
тогда это тоже не работает.
Сравнивая это так:
def filter_empty(self, queryset, value):
comment_count = Topic.objects.annotate(comment_count=Count('comments'))
if value is True:
return queryset.filter(comment_count < 1)
elif value is False:
return queryset.filter(comment_count >= 1)
else:
return queryset
вернулась другая ошибка: TypeError: '>=' not supported between instances of 'QuerySet' and 'int'.
И теперь у меня возникли трудности с разработкой правильного выражения фильтра для потенциального набора запросов. Поэтому я пришел сюда, чтобы попросить помощи и совета.
Если необходима какая-либо дополнительная информация/файлы, я готов их предоставить.
You .filter(…)
[Django-doc] on an .annotate(…)
[Django-doc] with:
def filter_empty(self, queryset, name, value):
queryset = Topic.objects.annotate(comment_count=Count('comments'))
if value is True:
return queryset.filter(comment_count__lt=1)
elif value is False:
return queryset.filter(comment_count__gte=2)
else:
return queryset