Фильтр 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