Django Swagger文档库drf-spectacular

一、概述

drf-spectacular 是一个为 Django REST Framework (DRF) 设计的 OpenAPI 3.0 和 3.1 规范的生成器。它旨在提供既理智又灵活的方式来创建 API 文档,主要实现以下三个目标:

从 DRF 中提取尽可能多的 schema 信息

提供灵活性,使 schema 在现实世界中可用(不仅仅是示例)

生成一个与最流行的客户端生成器兼容的 schema

官网:

https://drf-spectacular.readthedocs.io/en/latest/

先来看一个效果图吧

用户详情

用户更新

接下来会详细介绍,如何实现

二、安装

环境说明

python:3.12.3

django:5.0.7

djangorestframework:3.15.2

drf-spectacular:0.28.0

三、配置

修改django项目中的settings.py

注册app

复制代码
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
    'drf_spectacular',  # 接口文档 swagger
    'drf_spectacular_sidecar', # 接口文档 swagger-ui
]

将 AutoSchema 注册到 DRF 中

最后一行添加

复制代码
REST_FRAMEWORK = {
    # YOUR SETTINGS
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

修改一些默认配置

最后一行添加

复制代码
# drf-spectacular  配置
SPECTACULAR_SETTINGS = {
    'TITLE': '平台的API',
    'DESCRIPTION': 'Your project description',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
    # OTHER SETTINGS
    'SWAGGER_UI_DIST': 'SIDECAR',  # shorthand to use the sidecar instead
    'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
    'REDOC_DIST': 'SIDECAR',
}

添加路由

在项目主目录的url中添加

复制代码
from django.urls import path

from rest_framework.routers import DefaultRouter
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView

urlpatterns = [
    # YOUR PATTERNS
    path('doc/schema/', SpectacularAPIView.as_view(), name='schema'), # schema的配置文件的路由,下面两个ui也是根据这个配置文件来生成的
    path('doc/swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), # swagger-ui的路由
    path('doc/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), # redoc的路由
]

四、视图函数配置

完整视图函数如下:

复制代码
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework import viewsets
from rest_framework import status
from drf_spectacular.utils import extend_schema, OpenApiParameter
from drf_spectacular.types import OpenApiTypes
from django.http import JsonResponse
from django.db import transaction

from .modelsSerializers import *
from myapp.models import *
import json


@extend_schema(tags=["用户管理"])
class UserView(viewsets.ViewSet):
    @staticmethod
    def get_object(pk):
        """
        获取用户对象
        :param self:
        :param pk:
        :return:
        """
        try:
            obj = User.objects.get(pk=pk)
            return User.objects.get(pk=pk)
        except User.DoesNotExist:
            return None

    @extend_schema(
        operation_id="user-get",  # 设置右上角的名称,需要唯一性
        summary="用户列表",  # 接口上的备注 
    )
    def get(self, request, *args, **kwargs):
        """获取所有用户"""
        queryset = User.objects.all()
        serializer = UserSerializer(instance=queryset, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    @extend_schema(
        operation_id="user-post",  # 设置右上角的名称,需要唯一性
        summary="用户详情",  # 接口上的备注 
    )
    def post(self, request, pk, *args, **kwargs):
        """获取单个用户详细信息"""
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response(
                {"message": "user not found"}, status=status.HTTP_404_NOT_FOUND
            )
        serializer = UserSerializer(instance=obj)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    @extend_schema(
        operation_id="user-put",  # 设置右上角的名称,需要唯一性
        summary="用户更新",  # 接口上的备注
        # 执行序列化器
        responses=UserSerializer(many=True),
        # 对参数的修改
        parameters=[
            # 这是其中一个参数
            OpenApiParameter(
                # 参数的名称是done
                name="username",
                # 对参数的备注
                description="姓名",
                # 指定参数的类型
                type=OpenApiTypes.STR,
                # 指定必须给
                required=True,
                # 指定枚举项
                # enum = [True, False],
            ),
            OpenApiParameter(
                name="account", description="账号", type=OpenApiTypes.STR, required=True
            ),
            OpenApiParameter(
                name="is_superuser",
                description="是否是超级管理员1-是;2-否",
                type=OpenApiTypes.STR,
                required=True,
                enum=[1, 2],
            ),
            OpenApiParameter(
                name="is_active",
                description="是否活动状态1-是;2-否",
                type=OpenApiTypes.STR,
                required=True,
                enum=[1, 2],
            ),
            OpenApiParameter(
                name="phone", description="手机号", type=OpenApiTypes.STR, required=True
            ),
            OpenApiParameter(
                name="email", description="邮箱", type=OpenApiTypes.STR, required=True
            ),
            
            OpenApiParameter(
                name="role",
                description="角色1-管理员,2-普通用户",
                type=OpenApiTypes.STR,
                required=True,
                enum=[1, 2],
            ),
        ],
    )
    def put(self, request, pk):
        """更新单个用户"""
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response(
                {"message": "user not found"}, status=status.HTTP_404_NOT_FOUND
            )

        # 获取请求参数
        account = request.data.get("account")
        email = request.data.get("email")
        is_active = request.data.get("is_active")
        is_superuser = request.data.get("is_superuser")
        phone = request.data.get("phone")
        role = request.data.get("role")
        username = request.data.get("username")

        try:
            with transaction.atomic():  # 使用事务
                # 修改用户信息
                ret = User.objects.filter(pk=pk).update(
                    account=account,
                    email=email,
                    is_active=is_active,
                    is_superuser=is_superuser,
                    phone=phone,
                    role=role,
                    username=username,
                )
                if not ret:
                    return JsonResponse(
                        {
                            "status": status.HTTP_500_INTERNAL_SERVER_ERROR,
                            "data": [],
                            "msg": "修改用户失败",
                        },
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    )

                return JsonResponse(
                    {"status": status.HTTP_200_OK, "data": []},
                    status=status.HTTP_200_OK,
                )
        except Exception as e:
            print(e)
            return JsonResponse(
                {
                    "status": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "data": [],
                    "msg": f"{e}",
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    @extend_schema(
        operation_id="user-delete",  # 设置右上角的名称,需要唯一性
        summary="用户删除",  # 接口上的备注 
    )
    def delete(self, request, pk, *args, **kwargs):
        """更新单个用户"""
        obj = self.get_object(pk=pk)

        if obj is None:
            return Response(
                {"message": "user not found"}, status=status.HTTP_404_NOT_FOUND
            )
        obj.delete()

        return Response(status=status.HTTP_200_OK)

代码说明:

@extend_schema(tags=["用户管理"]) 定义标签名,显示效果就是这里

def get(self, request, *args, **kwargs):"""获取所有用户"""

注意看,3个引号部分,就是定义接口注释的,显示效果就是这里

@extend_schema(

operation_id="user-get", # 设置右上角的名称,需要唯一性summary="用户列表", # 接口上的备注

)

注意看,summary,就是定义接口描述的,显示效果就是这里

复制代码
@extend_schema(
        operation_id="user-put",  # 设置右上角的名称,需要唯一性
        summary="用户更新",  # 接口上的备注
        # 执行序列化器
        responses=UserSerializer(many=True),
        # 对参数的修改
        parameters=[
            # 这是其中一个参数
            OpenApiParameter(
                # 参数的名称是done
                name="username",
                # 对参数的备注
                description="姓名",
                # 指定参数的类型
                type=OpenApiTypes.STR,
                # 指定必须给
                required=True,
                # 指定枚举项
                # enum = [True, False],
            ),
            OpenApiParameter(
                name="account", description="账号", type=OpenApiTypes.STR, required=True
            ),
            OpenApiParameter(
                name="is_superuser",
                description="是否是超级管理员1-是;2-否",
                type=OpenApiTypes.STR,
                required=True,
                enum=[1, 2],
            ),
            OpenApiParameter(
                name="is_active",
                description="是否活动状态1-是;2-否",
                type=OpenApiTypes.STR,
                required=True,
                enum=[1, 2],
            ),
            OpenApiParameter(
                name="phone", description="手机号", type=OpenApiTypes.STR, required=True
            ),
            OpenApiParameter(
                name="email", description="邮箱", type=OpenApiTypes.STR, required=True
            ),
           
            OpenApiParameter(
                name="role",
                description="角色1-管理员,2-普通用户",
                type=OpenApiTypes.STR,
                required=True,
                enum=[1, 2],
            ),
        ],
    )

extend_schema,这个装饰器主要用于修改view在文档中的定义,参数意义如下:

  • operation_id:一个唯一标识ID,如果前端是使用这个接口文档生成的代码,那么这个参数将非常重要

  • parameters:添加到列表中的附加或替换参数去自动发现字段。

  • responses:修改序列化器。需要各种各样的可单独使用或组合使用的输入(有以下7种)

    • Serializer类 比如:Serializer
    • 序列化实例,比如:Serializer(many=True)
    • OpenApiTypes的基本类型或者实例 比如:OpenApiTypes.BOOL
    • OpenApiResponse类 例子见下面的备注
    • PolymorphicProxySerializer类
    • 1个字典,以状态码作为键, 以上其中一项作为值(是最常用的,格式 {200, None})
    • 1个字典,以状态码作为键,以media_type作为值 例子见下面的备注
  • request:替换序列化,接受各种输入

    • Serializer 类或者实例
    • OpenApiTypes基本类型或者实例
    • PolymorphicProxySerializer类
    • 1个字典,以media_type作为键,以上其中一项作为值
  • auth:用auth方法的显式列表替换发现的auth

  • description:替换发现的文档字符串

  • summary:一个可选的短的总结描述

  • deprecated:将操作标记为已弃用

  • tags:覆盖默认标记列表

  • exclude:设置为True以从schema中排除操作

  • operation:手动覆盖自动发现将生成的内容。你必须提供一个兼容OpenAPI3的字典,该字典可以直接翻译成YAML。

  • methods:检查extend_schema中特殊的方法,默认匹配所有

  • versions:检查extend_schema中特殊的API版本,默认匹配所有

  • example:将请求/响应示例附加到操作中

  • extensions:规范扩展

以上这些信息,显示效果就是这里

这里有一个问题,始终无法解决,就是你在swagger文档页面,调试某些接口,点击Execute,请求参数都是在url里面的,无法在body里面显示。

例如,我尝试调用修改用户接口

这里会出现500错误,提示没有username参数。因为视图函数,接收参数是从body中获取的,不是从url中获取的,所以会找不到。

但是如果使用postman调用,是没有任何问题的。

因为在extend_schema中,定义的参数,默认类型就是OpenApiParameter.QUERY,例如:

复制代码
# 这是其中一个参数
            OpenApiParameter(
                # 参数的名称是done
                name="username",
                # 对参数的备注
                description="姓名",
                # 指定参数的类型
                type=OpenApiTypes.STR,
                # 指定必须给
                required=True,
                # 指定枚举项
                # enum = [True, False],
                # 参数类型
                location=OpenApiParameter.QUERY,
            ),

当指定OpenApiParameter.QUERY作为参数的位置属性时,这表示该参数将在 HTTP 请求的查询字符串中传递。例如,在一个GET请求中,查询字符串是在 URL 中?之后的部分。

我用chatget搜索了一下,location只有以下几种类型

  1. QUERY

表示参数位于查询字符串(Query String)中。查询字符串是在 URL 中?之后的部分,通常用于GET请求传递参数。例如,在https://example.com/api/resource?param1 = value1&param2 = value2中,param1和param2的位置就是QUERY。

  1. PATH

用于表示参数是路径参数(Path Parameter)。路径参数是 URL 路径的一部分,用于识别特定的资源。例如,在https://example.com/api/users/{user_id}中,{user_id}就是路径参数,它的位置属性应该设置为PATH。

  1. HEADER

表示参数位于 HTTP 请求头(Header)中。请求头包含了关于请求的元数据,如Authorization(用于认证)、Content - Type(用于指定请求体的内容类型)等。

  1. COOKIE

当参数位于 HTTP 请求的 Cookie 中时,使用这个位置属性。Cookie 是服务器发送给浏览器,浏览器在后续请求中回传给服务器的一小段信息,常用于用户会话管理等。

根据以上结果,没有body,所以这个问题,只有等官方更新升级才能解决。

总结一下,swagger生成的文档,只需要观看即可,某些接口不能进行直接在swagger里面调用接口。

所以调用接口,还是需要专业工具,比如:postman或者代码实现。

本文参考链接:https://www.cnblogs.com/guangdelw/p/18054429

相关推荐
Victor35619 分钟前
Redis(65)如何优化Redis的AOF持久化?
后端
MZZDX23 分钟前
MySQL相关知识总结
数据库·mysql
Victor35624 分钟前
Redis(64)Redis的Lua脚本有哪些常见场景?
后端
青山撞入怀11142 小时前
sql题目练习——聚合函数
数据库·sql
Arva .2 小时前
面试题02
后端
disanleya2 小时前
MySQL默认端口为何是3306?修改后如何管理?
数据库·mysql·adb
川石课堂软件测试5 小时前
MySQL数据库之DBA命令
数据库·网络协议·mysql·http·单元测试·prometheus·dba
Bellafu6665 小时前
selenium常用的等待有哪些?
python·selenium·测试工具
小白学大数据6 小时前
Python爬虫常见陷阱:Ajax动态生成内容的URL去重与数据拼接
爬虫·python·ajax