Django Rest Framework如何使用Swagger或其他文档生成工具定义参数(request.POST)的自定义POST URL端点。

12

之前在Django 1.11中,我是这样定义Django REST API的:

在url.py中:

url(r'^api/test_token$', api.test_token, name='test_token'),

in api.py

@api_view(['POST'])
def test_token(request):
    # ----- YAML below for Swagger -----
    """
    description: test_token
    parameters:
      - name: token
        type: string
        required: true
        location: form       
    """
    token = request.POST['token']

    return Response("test_token success", status=status.HTTP_200_OK)

现在我正在迁移到Django 3.1.5,我想知道如何使用Django Rest Framework(DRF)以相同的方式实现上述内容。在上述特定情况下,是POST API“test_token”接受一个参数。并生成API文档,如swagger/redoc(可用于测试API)。

enter image description here

一些注释:

如何在Django 3.x上实现这个?(就像标题中写的:Django Rest Framework自定义POST URL端点并使用Swagger或其他文档)

更新:

我认为这里有一些解决方案:https://github.com/tfranzel/drf-spectacular/issues/279

由于我有很多使用@api_view的API,将docstring更改为装饰器@extend_schema可能是最简单的迁移路径。我希望有人能提供关于url.py的指导,以便使用@extend_schema进行转换。这是为了获得url端点和swagger的实现。谢谢。

这是我使用drf-spectacular最接近的结果。

@extend_schema( 
 parameters=[OpenApiParameter( 
     name='token', 
     type={'type': 'string'}, 
     location=OpenApiParameter.QUERY, 
     required=False, 
     style='form', 
     explode=False, 
 )], 
 responses=OpenApiTypes.OBJECT, 
) 
@api_view(['POST'])
def test_api(request):
    # ----- YAML below for Swagger -----
    """
    description: test_api
    parameters:
      - name: token
        type: string
        required: true
        location: form       
    """
    token = request.POST['token']
    
    return Response("success test_api:" + token, status=status.HTTP_200_OK)

它给出了这个结果(是错误的),注意令牌查询

curl -X POST "http://localhost:8000/api/test_token/?token=hello" -H  "accept: application/json" -H  "X-CSRFToken: JyPOSAQx04LK0aM8IUgUmkruALSNwRbeYDzUHBhCjtXafC3tnHRFsxvyg5SgMLhI" -d ""

使用{{POST输入参数}}的替代方法(如何获取?)

curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' --header 'X-CSRFToken: aExHCSwrRyStDiOhkk8Mztfth2sqonhTkUFaJbnXSFKXCynqzDQEzcRCAufYv6MC' -d 'token=hello' 'http://localhost:8000/api/test_token/

解决方案:

url.py

from drf_yasg.utils import swagger_auto_schema 

from rest_framework.response import Response
from rest_framework import status

from rest_framework.decorators import parser_classes
from rest_framework.parsers import FormParser

token = openapi.Parameter('token', openapi.IN_FORM, type=openapi.TYPE_STRING, required=True)
something = openapi.Parameter('something', openapi.IN_FORM, type=openapi.TYPE_INTEGER, required=False)
@swagger_auto_schema(
    method="post",
    manual_parameters=[token, something],
    operation_id="token_api"
)
@api_view(['POST'])
# this is optional and insures that the view gets formdata
@parser_classes([FormParser])
def token_api(request):
    token = request.POST['token']
    something = request.POST['something']
    
    return Response("success test_api:" + token + something, status=status.HTTP_200_OK)


schema_view = get_schema_view(
   openapi.Info(
      title="Snippets API",
      default_version='v1',
      description="Test description",
      terms_of_service="https://www.google.com/policies/terms/",
      contact=openapi.Contact(email="contact@snippets.local"),
      license=openapi.License(name="BSD License"),
   ),
   public=True,
   permission_classes=[permissions.AllowAny],
)


urlpatterns = [
    
    path('token_api', token_api, name='token_api'),

    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    
] + required_urlpatterns

你可以寻找 drf-spectacular 库。它得到了支持并且有很好的文档。它在包中提供了 swagger/redoc。https://drf-spectacular.readthedocs.io/en/latest/readme.html如果你需要自定义参数,可以在这里查看: https://drf-spectacular.readthedocs.io/en/latest/customization.html# - Marat Ablayev
你应该在Django 2.0中使用re_path来进行正则表达式匹配。将你的url更改为以下形式:from django.urls import re_path > re_path(r'^api/test_token$', api.test_token, name='test_token')。 - Siva Sankar
@MaratAblayev 谢谢。实际上,在您的第二个链接中,可能适用,因为我使用api_view,它说:我想知道那会是怎样的工作方式:“许多库使用“api_view”或APIView而不是ViewSet或GenericAPIView。在这些情况下,内省几乎没有可用的内容。此扩展的目的是增强或替换遇到的视图(仅用于模式生成)。通过一个queryset或serializer_class属性扩展发现的类Fixed(self.target_class)通常可以解决大多数问题。” - Axil
@MaratAblayev,我已经更新了一些信息。使用drf-spectacular的装饰器extend_schema非常接近,但无法将其定义为POST的输入参数。 - Axil
2个回答

7

正如您所说,django-rest-swagger已经不推荐使用。

因此建议使用drf-yasg

from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema    

class ArticleViewSet(viewsets.ModelViewSet):
    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT, 
        properties={
            'test_token': openapi.Schema(type=openapi.TYPE_STRING, description='string'),
        }
    ))
    def create(self, request, *args, **kwargs):
        ...

或者,如果你想使用DRF的动作(action)

    @swagger_auto_schema(method="post", request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT, 
        properties={
            'test_token': openapi.Schema(type=openapi.TYPE_STRING, description='string'),
        }
    ))
    @action(method=["post"], detail=False)
    def my_post_action(self, request, *args, **kwargs):
        ...

或者使用API视图:

# here we define that this view accepts a json (or object parameter) that has test_token parameter inside of it
@swagger_auto_schema(method='post', 
    request_body=openapi.Schema(
    type=openapi.TYPE_OBJECT, # object because the data is in json format
    properties={
        'test_token': openapi.Schema(type=openapi.TYPE_STRING, description='this test_token is used for...'),
    }
), operation_id="token_view")
# your view
@api_view(['POST'])
def token_view(request):
    pass

你的url.py文件将如下所示

# define some basic info about your api for swagger
schema_view = get_schema_view(
   openapi.Info(
      title="Snippets API",
      default_version='v1',
      description="Test description",
      terms_of_service="https://www.google.com/policies/terms/",
      contact=openapi.Contact(email="contact@snippets.local"),
      license=openapi.License(name="BSD License"),
   ),
   public=True,
   permission_classes=[permissions.AllowAny],
)

urlpatterns = [
    # define your api view url
    path('token_view/', token_view),
    # define the url of the swagger ui
    url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]

我不确定该如何做,我尝试下载了testproj并设置它,但是我不确定你是如何定义所有这些的。你能详细解释一下吗?https://github.com/axnsan12/drf-yasg/tree/master/testproj - Axil
好的,我以为你想要JSON格式。我会上传一个修复版本。 - Yuval
这是关于表单数据格式的内容:https://gist.github.com/hayke102/b392f9af89f9aaa63e9906ae5938b4ac - Yuval
我通过禁用 https://gist.github.com/axilaris/6269ee3898c7ad7465af820c5846de62,让它成功运行了。但是,CSRF似乎消失了。我认为需要找出如何在配置中至少启用CSRF。 - Axil
显示剩余15条评论

1

如果您只是想测试API,Django rest framework实际上带有自己的可浏览API功能。如果您在APIView上设置了一个serializer_class,那么BrowsableAPIRenderer将为您找出所有相关的详细信息。

以下内容应该会起作用:

from rest_framework import serializers, status
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView

class MySerializer(serializers.Serializer):
    token = serializers.CharField()

class MyView(GenericAPIView):

    serializer_class = MySerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.data

        return Response("test_token success", status=status.HTTP_200_OK)

# urls.py
urlpatterns = [
    ...
    path("api/test_token", views.MyView.as_view(), name="test_token")
]

(请注意,在Django 2+中,我们使用path而不是旧的url模式。如果您仍然想使用正则表达式模式,可以使用path_re)。

以上假设您没有更改呈现器的默认设置。默认值为:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

只需浏览到相关的端点,您就可以获得一个漂亮的测试界面。

在幕后,事实上是设置了serializer_class,这使得这一切成为可能。这与DRF自动生成用于swagger或redoc等工具的模式的方式相同。


在url.py文件中是否需要定义端点? - Axil
@Axil,不需要太多更改,只需在url.py中将您的端点指向与以前相同的视图(在这种情况下是基于类的视图)。请注意,自Django 2.0以来,我们使用path()而不是url()来定义我们的URL。它们具有非常相似的语法。如果您想使用旧的正则表达式语法,则可以使用path_re - tim-mccurrach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接