web-dev-qa-db-ja.com

Django REST Framework-Swaggerでクエリパラメータオプションを表示する方法

これはしばらく私を悩ませてきました。

最終的な目標は、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']

見てくれてありがとう、そして対応してくれてありがとう。

22
dajee

さて、この質問につまずいた人のために、私はそれを理解しました。それはかなりばかげており、知らないことで少し愚かだと感じますが、私の防御では、明確に文書化されていませんでした。情報は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のフォーム入力を配置します。続くもの--は、パラメーターの説明です。

20
dajee

新しいsw歩

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)
26
vadimchin

rest framework swagger docs を見つけました。したがって、パラメータタイプ(interger、char)、応答などを記述できます。

トリプル--- 必要です。

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

ModelViewSetsなどのmixinsクラスを使用する状況はどうですか。ドキュメントを追加するためだけに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
12
soooooot

免責事項:_Django_filters_を使用しているため、結果が異なる場合があります。 _Django_filters_は、DRF ViewSetで_filter_fields_パラメーターを使用します。これは、_Django_filters_を使用しない場合とは異なる場合があります。

このスレッド からインスピレーションを得て、フィルタリングバックエンドの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
        ]
_
1
Sean Chon

上記の回答について@vadimchinから詳しく説明します-これが実際の例です。

_# requirements.txt

djangorestframework==3.9.3
Django-rest-swagger==2.2.0
Django==2.2.1
coreapi==2.3.3
_

アプリケーションでビューセットを使用しています。 @jarussiが示唆するように、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
_
0
wji