Python 如何在 Django REST Framework 中显示查询参数选项 - Swagger

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28203070/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 02:54:36  来源:igfitidea点击:

How to show query parameter options in Django REST Framework - Swagger

pythondjangorestdjango-rest-framework

提问by dajee

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. Similar to how it is displayed when providing a serializer for POST.

我的最终目标是在 SwaggerUI 中显示查询参数选项,并为每个查询参数提供一个表单输入。类似于为 POST 提供序列化程序时的显示方式。

I am using a viewset which inherits from GenericViewSet and I have tried the following:

我正在使用从 GenericViewSet 继承的视图集,我尝试了以下操作:

  • provide filter_fieldsattribute
  • provide and set filter_backendsattribute to (filters.DjangoFilterBackend,)
  • provide filter_class defined inside my module.
  • Override optionsmethod to provide [actions][GET]information
  • 提供filter_fields属性
  • 提供并设置filter_backends属性(filters.DjangoFilterBackend,)
  • 提供在我的模块中定义的 filter_class。
  • options提供[actions][GET]信息的覆盖方法

Here's a small catch, I am not using any models so I don't think DjangoFilterBackend will really help me. 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.

这是一个小问题,我没有使用任何模型,所以我认为 DjangoFilterBackend 不会真正帮助我。我正在使用 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.

感谢您的关注,并提前感谢您的回复。

采纳答案by dajee

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. Instead it was found under django-rest-framework-docs, which is what Django REST Swagger is built off of.

好的,对于那些偶然发现这个问题的人,我已经弄清楚了。这是相当愚蠢的,我觉得不知道有点愚蠢,但在我的辩护中,它没有明确记录。在 DRF 文档或 Django REST Swagger 存储库中找不到该信息。相反,它是在 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. What follows --are the descriptions for the parameters.

swagger 将解析您的评论,并为 param1 和 param2 输入表单。下面--是对参数的说明。

回答by soooooot

I found the rest framework swagger docs. so we can write the parameter type(interger, char), response, etc.

我找到了其余框架 swagger docs。所以我们可以写参数类型(整数,字符),响应等。

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. Do we need to define the listfunction just to add the docs? -- No

我们使用 mixins 类的情况如何,例如ModelViewSets. 我们是否需要定义list函数来添加文档? - 不

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

回答by vadimchin

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)

回答by Sean Chon

Disclaimer: I am using django_filters, so results may vary. django_filtersuses the param filter_fieldsin the DRF ViewSet, which may be different than not using django_filters.

免责声明:我正在使用django_filters,因此结果可能会有所不同。django_filters使用filter_fieldsDRF ViewSet 中的参数,这可能与不使用django_filters.

I took inspiration from this threadand 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
        ]

回答by Sean Chon

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)按照@jarussi 的建议实施。

# 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

回答by Devaroop

Please refer this github issuewhich solves the problem.

请参考解决问题的这个 github问题。

回答by NiKo

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