Фильтр django-rest-framework по дате = нет
Я использую django-rest-framework
с django-filter
. Мне нужно получить список виджетов, где свойство date
равно None
, но независимо от того, какой запрос я пытался, я получаю либо пустые ответы, либо полные, нефильтрованные ответы.
Вот как я определил набор видов и фильтров.
class WidgetFilter(django_filters.FilterSet):
date = django_filters.DateTimeFilter(name='date', lookup_type='exact')
no_date = django_filters.DateTimefilter(name='date', lookup_type='isnull')
class Meta:
model = Widget
fields = ['date',]
class WidgetSet(viewsets.ModelViewSet):
model = Widget
filter_class = WidgetFilter
Следующие запросы приводят к пустым ответам []
:
?date=None
?date=0
?date=NULL
?date=False
?date=2012-05-24T11:20:06Z # a known and correct date
Следующие запросы возвращают все возвращаемые объекты:
?date=
?no_date=True
?no_date=False
?no_date=1
?no_date=0
Любая помощь очень ценится! Мне не удалось найти информацию об использовании дат (или передав None
в качестве значения фильтра) с помощью django-filter
через django-rest-framework
.
В случае, если нет более элегантного способа, вот как я использовал свое обходное решение, но мне все равно хотелось бы узнать о решении, которое использует django-filter
, если оно существует.
class WidgetSet(viewsets.ModelViewSet):
model = Widget
def get_queryset(self):
if 'no_date' in self.request.QUERY_PARAMS:
return self.model.objects.filter(date=None)
return self.model.objects.all()
Ответы
Ответ 1
Задание isnull
непосредственно в аргументе filter name
как 'date__isnull'
, похоже, работает для меня с Django REST Framework 3.1.3.
class WidgetFilter(django_filters.FilterSet):
date = django_filters.DateTimeFilter(name='date')
no_date = django_filters.BooleanFilter(name='date__isnull')
class Meta:
model = Widget
fields = []
Ответ 2
Сегодня я столкнулся с подобной ситуацией и кажется, что из-за рамки django rest framework * поддерживает этот фильтр как:
~/your_endpoint/?date__isnull=True
Это соответствует тому, как будет выглядеть эквивалентный запрос ORM. Если это уродливо, вы можете использовать пример docs, чтобы преобразовать этот параметр запроса в что-то другое, без необходимости переопределять get_queryset
- Я использую 2.4.3, но я не верю, что это новая вещь.
Ответ 3
В случае, если нет более элегантного способа, вот как я применил свое обходное решение, но мне все равно хотелось бы узнать о решении, которое использует django-filter
, если оно существует.
class WidgetSet(viewsets.ModelViewSet):
model = Widget
def get_queryset(self):
if 'no_date' in self.request.QUERY_PARAMS:
return self.model.objects.filter(date=None)
return self.model.objects.all()
Ответ 4
Я сделал это для фильтров выбора, который (возможно) более полезен:
class NullableChoiceFilter(django_filters.ChoiceFilter):
def __init__(self, **kwargs):
choices = dict(kwargs['choices'])
null_text = choices.pop(None, 'null')
kwargs['choices'] = ((None, '------'), ('null', null_text)) + tuple(choices.items())
super().__init__(**kwargs)
def filter(self, qs, value):
if value == 'null':
return super().filter(qs, Lookup(lookup_type='isnull', value=True))
else:
return super().filter(qs, value)
а затем
class MyFilterSet(filters.FilterSet):
class Meta:
model = ...
@classmethod
def filter_for_lookup(cls, f, lookup_type):
if lookup_type == 'exact' and f.choices:
return NullableChoiceFilter, {'choices': f.choices}
return filters.FilterSet.filter_for_lookup(f, lookup_type)
Я знаю, что это не отвечает именно на ваш вопрос, но это первый результат google для "django rest framework filter null."
Ответ 5
Запуск django-filter==1.0.4
и djangorestframework==3.6.3
.
Правильный ответ не сработал, потому что пути модулей изменились в django-filter
(BooleanFilter переместился в django_filters.rest_framework).
И __isnull
тоже не работал, мне пришлось использовать lookup_expr:
from django_filters import rest_framework as filters
class WidgetFilter(filters.FilterSet):
no_date = filters.BooleanFilter(name='date', lookup_expr='isnull')
class Meta:
model = Widget
fields = ( 'date')
Получил ответ от https://github.com/carltongibson/django-filter/issues/743
Теперь я могу фильтровать "no date" с помощью http://localhost:8000/widgets/?no_date=True