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

时间:2015-01-28 21:50:09

标签: python django rest django-rest-framework

这一直困扰着我一段时间。

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

我正在使用一个继承自GenericViewSet的视图集,我尝试了以下内容:

  • 提供filter_fields属性
  • 提供并将filter_backends属性设置为(filters.DjangoFilterBackend,)
  • 提供在我的模块中定义的filter_class。
  • 覆盖options方法以提供[actions][GET]信息

这里有一个小小的问题,我没有使用任何模型,所以我不认为DjangoFilterBackend会真正帮助我。我正在使用DjangoRESTFramework与外部API进行通信,我只是简单地获取JSON结果,并将其传递给前端层。

以下是我的代码的一个小修改代码片段,以便更好地解释我的问题:

views.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

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']

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

8 个答案:

答案 0 :(得分:26)

新招摇 来自rest_framework.filters导入BaseFilterBackend 进口coreapi class SimpleFilterBackend(BaseFilterBackend):     def get_schema_fields(self,view):         返回[coreapi.Field(             名称=“查询”,             位置=“查询”,             需要=假             类型=“字符串”         )] class MyViewSet(viewsets.ViewSet):     filter_backends =(SimpleFilterBackend,)     def list(self,request,* args,** kwargs):         #print(request.GET.get('query'))#在视图中使用查询参数         return Response({'hello':'world'},status.HTTP_200_OK)

答案 1 :(得分:20)

好的,对于那些偶然发现这个问题的人,我已经弄明白了。这是相当愚蠢的,我觉得有点愚蠢不知道,但在我的辩护中,它没有明确记录。在DRF文档中或Django REST Swagger存储库中找不到该信息。相反,它是在django-rest-framework-docs下找到的,这就是Django REST Swagger的基础。

要指定您的查询参数作为表单字段显示在SwaggerUI中,您只需这样评论:

def list(self):
    """
    param1 -- A first parameter
    param2 -- A second parameter
    """ 
    ...

swagger会解析你的评论,并会为param1和param2输入一个表单。 --后面的内容是参数的说明。

答案 2 :(得分:12)

我找到了rest framework swagger docs。 所以我们可以编写参数类型(整数,字符),响应等

三重奏---是必要的。

@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
    """

我们使用mixins类如ModelViewSets的情况如何。 我们是否需要定义list函数才能添加文档? - 没有

我们可以这样做:

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

答案 3 :(得分:1)

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

我从this thread中汲取了灵感,并通过以下方式覆盖了过滤后端中的get_schema_fields()方法。

settings.py

REST_FRAMEWORK = {
    ...
    'DEFAULT_FILTER_BACKENDS': ('location.of.custom_backend.CustomDjangoFilterBackend')
    ...
}

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
        ]

答案 4 :(得分:1)

使用openapi(而不是coreapi),我发现的“最简单”方法是通过以下core dev comment

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

答案 5 :(得分:0)

详细说明@vadimchin的上述答案-这是一个有效的示例。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    if collectionView == filterCollectionView {
        return CGSize(width: collectionView.frame.size.width / 4, height: collectionView.frame.size.height)
    } else {
        return CGSize(width: collectionView.frame.size.width, height: collectionView.frame.size.height)
    }
}

我在我的应用程序中使用了Viewsets。我必须按照@jarussi的建议实施# requirements.txt djangorestframework==3.9.3 django-rest-swagger==2.2.0 django==2.2.1 coreapi==2.3.3

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,)

答案 6 :(得分:0)

请参考this github issue来解决问题。

答案 7 :(得分:0)

如果在过滤器后端使用查询参数,添加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]