[英]How to show query parameter options in Django REST Framework - Swagger
This has been bugging me for a while now.这一直困扰着我一段时间。
My ultimate goal is to show query parameter options inside SwaggerUI and give a form input for each query parameter.我的最终目标是在 SwaggerUI 中显示查询参数选项,并为每个查询参数提供一个表单输入。 Similar to how it is displayed when providing a serializer for POST.
类似于为 POST 提供序列化程序时的显示方式。
I am using a viewset which inherits from GenericViewSet and I have tried the following:我正在使用从 GenericViewSet 继承的视图集,并且我尝试了以下方法:
filter_fields
attributefilter_fields
属性filter_backends
attribute to (filters.DjangoFilterBackend,)
filter_backends
属性设置为(filters.DjangoFilterBackend,)
options
method to provide [actions][GET]
informationoptions
方法以提供[actions][GET]
信息Here's a small catch, I am not using any models so I don't think DjangoFilterBackend will really help me.这是一个小问题,我没有使用任何模型,所以我认为 DjangoFilterBackend 不会真正帮助我。 I am using DjangoRESTFramework to talk to an outside API, and I am simply getting JSON result back, and passing it through to the frontend layer.
我正在使用 DjangoRESTFramework 与外部 API 对话,我只是将 JSON 结果返回,并将其传递给前端层。
Here is a small modified snippet of my code to better explain my problem:这是我的代码的一小段修改,以更好地解释我的问题:
views.py视图.py
class SomeViewSet(GenericViewSet):
# Note that I have all of these defined, but I have tried various combinations
filter_fields = ('query_option_1', 'query_option_2',)
filter_backeds = (filters.DjangoFilterBackend,)
filter_class = SomeFilter
query_metadata = some_dict
# This works when request is OPTIONS
def options(self, request, *args, **kwargs):
if self.metadata_class is None:
return self.http_method_not_allowed(request, *args, **kwargs)
data = self.metadata_class().determine_metadata(request, self)
data['actions']['GET'] = self.query_metadata
return Response(data, status=status.HTTP_200_OK)
filters.py过滤器.py
class SomeFilter(FilterSet):
strict = True
query_option_1 = django_filters.NumberFilter(name='query_option_1')
query_option_2 = django_filters.NumberFilter(name='query_option_2')
class Meta:
fields = ['query_option_1', 'query_option_2']
Thank you for looking, and thanks in advance for responding.感谢您的关注,并提前感谢您的回复。
New swagger新招摇
from rest_framework.filters import BaseFilterBackend
import coreapi
class SimpleFilterBackend(BaseFilterBackend):
def get_schema_fields(self, view):
return [coreapi.Field(
name='query',
location='query',
required=False,
type='string'
)]
class MyViewSet(viewsets.ViewSet):
filter_backends = (SimpleFilterBackend,)
def list(self, request, *args, **kwargs):
# print(request.GET.get('query')) # Use the query param in your view
return Response({'hello': 'world'}, status.HTTP_200_OK)
Okay, for those who stumble upon this question, I have figured it out.好的,对于那些偶然发现这个问题的人,我已经弄清楚了。 It is rather silly, and I feel a little stupid for not knowing, but in my defense, it was not clearly documented.
这是相当愚蠢的,我觉得不知道有点愚蠢,但在我的辩护中,它没有明确记录。 The information was not found in DRF documentation, or inside Django REST Swagger repository.
在 DRF 文档或 Django REST Swagger 存储库中找不到该信息。 Instead it was found under django-rest-framework-docs, which is what Django REST Swagger is built off of.
相反,它是在 django-rest-framework-docs 下找到的,这是 Django REST Swagger 的构建基础。
To specify your query parameter to show up in your SwaggerUI as a form field, you simply comment like so:要指定您的查询参数作为表单字段显示在您的 SwaggerUI 中,您只需像这样评论:
def list(self):
"""
param1 -- A first parameter
param2 -- A second parameter
"""
...
And swagger will parse your comments and will put a form input for param1 and param2. swagger 将解析您的评论,并为 param1 和 param2 输入表单。 What follows
--
are the descriptions for the parameters.接下来
--
对于参数的描述。
I found the rest framework swagger docs .我找到了 其余框架 swagger docs 。 so we can write the parameter type(interger, char), response, etc.
所以我们可以写参数类型(整数,字符),响应等。
the tripple ---
is necessary.三元组
---
是必要的。
@api_view(["POST"])
def foo_view(request):
"""
Your docs
---
# YAML (must be separated by `---`)
type:
name:
required: true
type: string
url:
required: false
type: url
created_at:
required: true
type: string
format: date-time
serializer: .serializers.FooSerializer
omit_serializer: false
parameters_strategy: merge
omit_parameters:
- path
parameters:
- name: name
description: Foobar long description goes here
required: true
type: string
paramType: form
- name: other_foo
paramType: query
- name: other_bar
paramType: query
- name: avatar
type: file
responseMessages:
- code: 401
message: Not authenticated
"""
How about the situation we use the mixins class such as ModelViewSets
.怎么样的情况,我们使用混入类如
ModelViewSets
。 Do we need to define the list
function just to add the docs?我们是否需要定义
list
函数来添加文档? -- No - 不
We can do like this:我们可以这样做:
class ArticleViewSet(viewsets.ModelViewSet):
"""
Articles.
---
list: #<--- here!!
parameters:
- name: name
description: article title
get_price:
omit_serializer: true
"""
@list_route(methods=['get'])
def get_price(self, request):
pass
Working with openapi (and not coreapi), the "simplest" way I found is from this core dev comment :使用 openapi(而不是 coreapi),我发现的“最简单”的方法来自这个核心开发评论:
from rest_framework.schemas.openapi import AutoSchema
class CustomSchema(AutoSchema):
def get_operation(self, path, method):
op = super().get_operation(path, method)
op['parameters'].append({
"name": "foo",
"in": "query",
"required": True,
"description": "What foo does...",
'schema': {'type': 'string'}
})
return op
class MyViewSet(ModelViewSet):
schema = CustomSchema()
def get_queryset(self):
foo = self.request.query_params.get("foo")
if foo:
self.queryset = self.queryset.filter(foo=foo)
return self.queryset
Disclaimer: I am using django_filters
, so results may vary.免责声明:我正在使用
django_filters
,所以结果可能会有所不同。 django_filters
uses the param filter_fields
in the DRF ViewSet, which may be different than not using django_filters
. django_filters
使用 DRF ViewSet 中的参数filter_fields
,这可能与不使用django_filters
不同。
I took inspiration from this thread and overrode the get_schema_fields()
method in the filtering backend in the following way.我从这个线程中获得灵感,并通过以下方式覆盖了过滤后端中的
get_schema_fields()
方法。
settings.py设置.py
REST_FRAMEWORK = {
...
'DEFAULT_FILTER_BACKENDS': ('location.of.custom_backend.CustomDjangoFilterBackend')
...
}
custom_backend.py custom_backend.py
import coreapi
import coreschema
from django_filters.rest_framework import DjangoFilterBackend
class CustomDjangoFilterBackend(DjangoFilterBackend):
"""
Overrides get_schema_fields() to show filter_fields in Swagger.
"""
def get_schema_fields(self, view):
assert (
coreapi is not None
), "coreapi must be installed to use `get_schema_fields()`"
assert (
coreschema is not None
), "coreschema must be installed to use `get_schema_fields()`"
# append filter fields to existing fields
fields = super().get_schema_fields(view)
if hasattr(view, "filter_fields"):
fields += view.filter_fields
return [
coreapi.Field(
name=field,
location='query',
required=False,
type='string',
) for field in fields
]
Elaborating on the answers above from @vadimchin - here is a working example.详细说明@vadimchin 上面的答案 - 这是一个工作示例。
# requirements.txt
djangorestframework==3.9.3
django-rest-swagger==2.2.0
django==2.2.1
coreapi==2.3.3
I am using Viewsets in my application.我在我的应用程序中使用视图集。 I had to implement
filter_queryset(self, request, queryset, view)
as suggested by @jarussi.我必须按照
filter_queryset(self, request, queryset, view)
建议实现filter_queryset(self, request, queryset, view)
。
# models.py
from django.db import models
class Recording(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=511)
# serializers.py
from models import Recording
from rest_framework import serializers
class RecordingSerializer(serializers.ModelSerializer):
class Meta:
model = Recording
fields = '__all__'
# views.py
from rest_framework import viewsets
from filters import NameFilterBackend
from serializers import RecordingSerializer
class RecordingViewSet(viewsets.ModelViewSet):
serializer_class = RecordingSerializer
queryset = Recording.objects.all()
filter_backends = (NameFilterBackend,)
# filters.py
from rest_framework.filters import BaseFilterBackend
import coreapi
class NameFilterBackend(BaseFilterBackend):
def get_schema_fields(self, view):
return [coreapi.Field(
name='name',
location='query',
required=False,
type='string',
description='name of recording'
)]
def filter_queryset(self, request, queryset, view):
try:
n = request.query_params['name']
queryset = queryset.filter(name=n)
except KeyError:
# no query parameters
pass
return queryset
请参考解决问题的 这个 github问题。
If the query parameters are used in a filter backend, adding a get_schema_operation_parameters
method is the simplest solution:如果在过滤器后端使用查询参数,添加一个
get_schema_operation_parameters
方法是最简单的解决方案:
class SimpleFilterBackend(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
foo = request.query_params.get("foo")
if foo:
queryset = queryset.filter(foo=foo)
return queryset
def get_schema_operation_parameters(self, view):
return [{
"name": "foo",
"in": "query",
"required": True,
"description": "What foo does...",
"schema": {"type": "string"}
}]
class MyViewSet(ModelViewSet):
filter_backends = [SimpleFilterBackend]
For anyone stumbling upon this later, I pieced together a few solutions and came up with this:对于后来偶然发现的任何人,我拼凑了一些解决方案并提出了这个:
This is using the new openapi
instead of coreapi
.这是使用新的
openapi
而不是coreapi
。
I subclassed AutoSchema
to accept a dictionary keyed on action name and mapping to the OpenApi Operation Parameter object spec.我
AutoSchema
子类化以接受以操作名称为键的字典并映射到 OpenApi 操作参数 object 规范。 These params get appended to the operation.这些参数被附加到操作中。
from rest_framework.schemas.openapi import AutoSchema
class ParameterSchema(AutoSchema):
def __init__(self, **kwargs):
self.parameters = kwargs.pop("parameters")
super().__init__(**kwargs)
def get_operation(self, path, method):
op = super().get_operation(path, method)
method_name = getattr(self.view, "action", method.lower())
action_parameters = self.parameters.get(method_name, [])
for param in action_parameters:
op["parameters"].append(param)
return op
class MyViewSet(viewsets.ModelViewSet):
schema = ParameterSchema(
parameters={
"list": [
{
"name": "my-param",
"in": "query",
"required": False,
"description": "Description on the param",
"schema": {"type": "boolean", "default": False},
}
]
}
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.