Django rest framework DRF 3.7 autogen文档中的条件筛选器集:我是否可以为路由添加queryparam筛选器(但仅适用于某些HTTP谓词)

Django rest framework DRF 3.7 autogen文档中的条件筛选器集:我是否可以为路由添加queryparam筛选器(但仅适用于某些HTTP谓词),django-rest-framework,django-filter,Django Rest Framework,Django Filter,(DRF v3.7,django过滤器v1.1.0) 嗨!我有一个工作过滤器集,可以通过查询参数过滤结果,例如http://localhost:9000/mymodel?name=FooOnly 这很好用 class MyNameFilter(FilterSet): name = CharFilter(field_name='name', help_text='Filter by name') class Meta: model = MyModel

(DRF v3.7,django过滤器v1.1.0)

嗨!我有一个工作过滤器集,可以通过查询参数过滤结果,例如
http://localhost:9000/mymodel?name=FooOnly

这很好用

class MyNameFilter(FilterSet):
    name = CharFilter(field_name='name', help_text='Filter by name')

    class Meta:
        model = MyModel
        fields = ('name',)


class MyModel(...):
    ...
    filter_backends = (DjangoFilterBackend,)
    filter_class = MyNameFilter
但是,当我为我的API呈现内置自动生成的文档时,我看到这个查询参数记录了我路线中的所有方法,例如,
GET
PUT
PATCH
,等等

我只打算通过此查询参数筛选其中一些HTTP谓词,因为它对其他谓词没有意义,例如,
PUT

有没有一种好方法可以使我的过滤器集以这种方式有条件?条件路由方法

我试着在路由器层面上应用这个逻辑(一个错误的想法)。同样在视图集级别——但是没有
get\u filter\u class
覆盖方法,例如
get\u serializer\u class


谢谢您的帮助。

您将在
DjangoFilterBackend
中获得
get\u filter\u类
。您需要创建一个新的
FilterBackend
,它覆盖
filter\u queryset
方法

class GETFilterBackend(DjangoFilterBackend):

    def filter_queryset(self, request, queryset, view):
        if request.method == 'GET':
            return super().filter_queryset(request, queryset, view)
        return queryset


class MyModel(...):
    ...
    filter_backends = (GETFilterBackend,)
    filter_class = MyNameFilter

在Carlton G.的帮助下,在django filters Google Groups论坛(谢谢你,Carlton)上解决了这个问题

我的解决方案是升级到一个级别,拦截AutoSchema检查中产生的CoreAPI模式,但在它进入自动生成的文档之前

在拦截的这一点上,我覆盖
。\u允许\u过滤器
仅应用于我感兴趣的HTTP动词。(尽管前缀为
,因此是一个不用于重写的私有方法,但该方法的注释明确鼓励这种做法。
在v3.7中引入:最初为“私有”(即带前导下划线),允许根据用户体验进行更改。

我的代码如下:

from rest_framework.schemas import AutoSchema


# see https://www.django-rest-framework.org/api-guide/schemas/#autoschema
#     and https://www.django-rest-framework.org/api-guide/filtering/

class LimitedFilteringViewSchema(AutoSchema):
    # Initially copied from lib/python2.7/site-packages/rest_framework/schemas/inspectors.py:352,
    # then modified to restrict our filtering by query-parameters to only certain view
    # actions or HTTP verbs
    def _allows_filters(self, path, method):
        if getattr(self.view, 'filter_backends', None) is None:
            return False

        if hasattr(self.view, 'action'):
            return self.view.action in ["list"]  # original code:  ["list", "retrieve", "update", "partial_update", "destroy"]

        return method.lower() in ["get"]  # original code:  ["get", "put", "patch", "delete"]
然后,在我的APIView级别:

class MyViewSchema(LimitedFilteringViewSchema):

    # note to StackOverflow:  this was some additional schema repair work I 
    # needed to do, again adding logic conditional on the HTTP verb.  
    # Not related to the original question posted here, but hopefully relevant
    # all the same.

    def get_serializer_fields(self, path, method):
        fields = super(MyViewSchema, self).get_serializer_fields(path, method)

        # The 'name' parameter is set in MyModelListItemSerializer as not being required.
        # However, when creating an access-code-pool, it must be required -- and in DRF v3.7, there's
        # no clean way of encoding this conditional logic, short of what you see here:
        #
        # We override the AutoSchema inspection class, so we can intercept the CoreAPI Fields it generated,
        # on their way out but before they make their way into the auto-generated api docs.
        #
        # CoreAPI Fields are named tuples, hence the poor man's copy constructor below.

        if path == u'/v1/domains/{domain_name}/access-code-pools' and method == 'POST':
            # find the index of our 'name' field in our fields list
            i = next((i for i, f in enumerate(fields) if (lambda f: f.name == 'name')(f)), -1)
            if i >= 0:
                name_field = fields[i]
                fields[i] = Field(name=name_field.name, location=name_field.location,
                                  schema=name_field.schema, description=name_field.description,
                                  type=name_field.type, example=name_field.example,
                                  required=True)  # all this inspection, just to set this here boolean.
        return fields


class MyNameFilter(FilterSet):
    name = CharFilter(field_name='name', help_text='Filter returned access code pools by name')

    class Meta:
        model = MyModel
        fields = ('name',)


class MyAPIView(...)

    schema = MyViewSchema()
    filter_backends = (DjangoFilterBackend,)
    filter_class = MyNameFilter



谢谢。我应该补充一点,我也尝试过这个解决方案。问题是,它不会阻止auto gen文档在不应该的地方列出我的查询参数。我认为这有两个部分:API本身的功能(它做什么,不做什么)。还有内置的autogen文档。上述内容确保了功能方面。Queryparam筛选只会在应该的地方进行。但文档方面仍然不正确。这不仅仅是一个理想文档的问题,例如我的Queryparam(“名称”)是的,上面的解决方案将确保严格按照
GET
方法进行过滤。因为过滤也将应用于
GET\u对象
方法,该方法由
UpdateModelMixin
使用。文档方面我认为这不起作用。