У меня есть набор представлений, который должен иметь как гибкое упорядочение по параметру, так и фильтрацию по параметру для пользовательского переопределения list(). Я могу заставить работать порядок, а также фильтрацию по различным параметрам через django-filter, но я не могу заставить их работать одновременно.

Вот мой упрощенный код views.py, который работает для упорядочивания результатов:

class AssetViewSet(viewsets.GenericViewSet, AssetPaginationMixin,):

    queryset = Asset.objects.all()
    pagination_class = AssetPagination
    serializer_class = serializers.AssetSerializer
    filter_backends = (OrderingFilter, )
    ordering_fields = ('id', 'session_id')
    filter_class = AssetFilterSet

    def list(self, request):
        assets = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(assets, many=True)
        return Response(serializer.data)

А вот код, который работает для фильтрации:

class AssetViewSet(viewsets.GenericViewSet, AssetPaginationMixin,):

    queryset = Asset.objects.all()
    pagination_class = AssetPagination
    serializer_class = serializers.AssetSerializer
    filter_backends = (OrderingFilter, )
    ordering_fields = ('id', 'session_id')
    filter_class = AssetFilterSet

    def list(self, request):
        assets = AssetFilterSet(request.query_params)
        serializer = self.get_serializer(assets, many=True)
        return Response(serializer.data)

И, наконец, мой код filters.py:

class AssetFilterSet(django_filters.FilterSet):
    project_id = django_filters.NumberFilter()
    submitted = django_filters.TypedChoiceFilter(choices=BOOLEAN_CHOICES, coerce=strtobool) 
    class Meta:
        model = Asset
        fields = ['project',
                  'submitted']

Единственное отличие - это первая строка в list(). По какой-то причине кажется, что AssetFilterSet нужно применять непосредственно в list(), чтобы вступить в силу, и в противном случае он будет пропущен, если я использую self.filter_queryset в list(), несмотря на то, что указано автор: filter_class = AssetFilterSet.

1
hburgund 17 Дек 2017 в 21:41

1 ответ

Лучший ответ

Я отвечу на свой вопрос. Оказывается, это очень простое решение; вы должны явно указать ОБЕ DjangoFilterBackend и OrderingFilter как filter_backends, несмотря на то, что DjangoFilterBackend задан глобально в НАСТРОЙКАХ.

Вот рабочий код:

class AssetViewSet(viewsets.GenericViewSet, AssetPaginationMixin,):

    queryset = Asset.objects.all()
    pagination_class = AssetPagination
    serializer_class = serializers.AssetSerializer
    filter_backends = (DjangoFilterBackend, OrderingFilter,)
    ordering_fields = ('id', 'session_id')
    filter_class = AssetFilterSet

    def list(self, request):
        assets = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(assets, many=True)
        return Response(serializer.data)

У меня создалось впечатление, что указание DjangoFilterBackend в НАСТРОЙКАХ означает, что он будет включен по умолчанию, а добавление фильтра filter_backends добавит к нему, а не заменит его. Живи и учись!

1
hburgund 19 Дек 2017 в 03:12