简体   繁体   English

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

[英]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 继承的视图集,并且我尝试了以下方法:

  • provide filter_fields attribute提供filter_fields属性
  • provide and set filter_backends attribute to (filters.DjangoFilterBackend,)提供并将filter_backends属性设置为(filters.DjangoFilterBackend,)
  • provide filter_class defined inside my module.提供在我的模块中定义的 filter_class。
  • Override options method to provide [actions][GET] information覆盖options方法以提供[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.

相关问题 如何在django-rest-swagger中指定查询参数序列化程序? - How to specify a query parameter serializer in django-rest-swagger? 在Swagger中为Django Rest Framework显示最大值,最小值和默认值 - Show maximum, minimum and default in Swagger for Django Rest Framework Django Rest Framework,Swagger和CORS - Django Rest Framework, Swagger and CORS Django REST框架+ Django REST Swagger + ImageField - Django REST Framework + Django REST Swagger + ImageField 如何将swagger-ui与Django Rest Framework和Django-Rest-framwork-Swagger集成? - How to integrate swagger-ui with Django Rest Framework and Django-Rest-framwork-Swagger? Django Rest Framework:如何为基于函数的视图启用 swagger 文档 - Django Rest Framework: How to enable swagger docs for function based views Django REST框架Swagger - 身份验证错误 - Django REST Framework Swagger - Authentication Error Django REST 框架 - 使用日期和字符串参数过滤查询参数 - Django REST framework - filtering against query params with date and string parameter 在Django REST Framework中,如何基于GET查询参数初始化createAPIView的字段值? - In Django REST Framework, how to initialize a field value for a createAPIView based on the GET query parameter? 如何在django-rest-framework中使用查询参数进行详细视图查找? - How do I use a query parameter for a detail view lookup with django-rest-framework?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM