问题描述
以前在 Django 1.11 中,我以这种方式定义了 Django REST API:
在 url.py
url(r'^api/test_token$',api.test_token,name='test_token'),
在 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”接受一个参数。并生成 swagger/redoc 等 API 文档(可用于测试 API)
一些注意事项:
- 此处还指出 django-rest-swagger 已于 2019 年 6 月弃用 django-rest-swagger UI doesn't have form for POST request body (function based view)
- 需要注意的是,它使用 request.POST(表单数据)作为参数 https://www.django-rest-framework.org/tutorial/2-requests-and-responses/
- 在 Django 1.11.x 中,我使用了这个 swagger_schema.py - https://gist.github.com/axilaris/b7152215a76f6f1f5ffca0436991328d
我如何在 Django 3.x 上实现这个? (如标题所示:带有 Swagger 或其他文档定义的参数的 Django Rest Framework 自定义 POST URL 端点)
更新:
我认为这里有某种形式的解决方案: https://github.com/tfranzel/drf-spectacular/issues/279
因为我有很多使用@api_view 的 API,所以更改文档字符串 到装饰器 @extend_schema 可能是最简单的迁移路径。我希望有人可以为使用@extend_schema 的转换提供有关 url.py 的指导。这是为了实现 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',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
解决方法
正如您所说,不推荐使用 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 操作
@swagger_auto_schema(method="post",request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,}
))
@action(method=["post"],detail=False)
def my_post_action(self,**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'),]
,
如果您只是想测试 API,Django rest 框架实际上带有它自己的可浏览 API。如果您在 serializer_class
上设置 APIView
,那么 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,**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 之类的架构的方式相同。