Django rest framework DRF 3.7 autogen文档中的条件筛选器集:我是否可以为路由添加queryparam筛选器(但仅适用于某些HTTP谓词)
(DRF v3.7,django过滤器v1.1.0) 嗨!我有一个工作过滤器集,可以通过查询参数过滤结果,例如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
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
使用。文档方面我认为这不起作用。