下载工作台
Django Web 开发

drf-spectacular 与 OpenAPI 文档

试读上半部分 · 解锁后可读全文

第 14 章 · drf-spectacular 与 OpenAPI 文档

本章目标:安装配置 drf-spectacular;理解 SPECTACULAR_SETTINGS;使用 @extend_schema 文档化请求体、响应与错误码;暴露 Swagger UIRedoc;预留 Bearer JWT 安全方案;与 Flask ch14 Flask-RESTX 对照,为 shop-demo /api/ 提供可交互契约。

学时建议:4~5 小时(含 2 小时文档站联调)

前置:本模块 ch01~ch13;重点复习 ch07 DRF 路由、ch13 ProductListSerializer / ProductWriteSerializer 字段定义。


14.1 为什么需要 API 文档

┌─────────────┐     OpenAPI 契约      ┌─────────────┐
│  user-demo   │ ◄──────────────────► │  shop-demo   │
│  前端 SPA    │   路径/参数/响应模型   │  Django API  │
└─────────────┘                       └─────────────┘
         └──────── Swagger UI 在线调试 ──────────┘
无文档有 OpenAPI 文档
口头同步字段,易漂移单一契约,版本可追踪
联调靠猜状态码错误码与示例一目了然
新人上手慢/api/schema/swagger-ui/ 自助试调
前端 Mock 手写从 schema 生成类型(选修)

OpenAPI 3 核心:paths(路径与方法)、components/schemas(模型)、responses(状态码)、securitySchemes(Bearer,ch15 实装)。

示例域名:api.example.com;前端:user-demo;禁止写入真实生产密钥。

14.2 安装 drf-spectacular

cd ~/python-learn/shop-demo
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install "drf-spectacular>=0.27,<1"
pip freeze | grep spectacular >> requirements.txt

shopdemo/settings.py

INSTALLED_APPS = [
    # ...
    "rest_framework",
    "drf_spectacular",
    "catalog",
]

REST_FRAMEWORK = {
    # ... ch07 已有配置
    "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
}

SPECTACULAR_SETTINGS = {
    "TITLE": "shop-demo API",
    "DESCRIPTION": "教学项目 · 商品与订单 REST API(虚构 api.example.com 契约)",
    "VERSION": "1.0.0",
    "SERVE_INCLUDE_SCHEMA": False,
    "COMPONENT_SPLIT_REQUEST": True,       # 读写模型分离
    "SCHEMA_PATH_PREFIX": r"/api",
    "TAGS": [
        {"name": "products", "description": "商品资源"},
        {"name": "auth", "description": "认证(ch15 JWT)"},
    ],
    "SECURITY": [{"BearerAuth": []}],
    "APPEND_COMPONENTS": {
        "securitySchemes": {
            "BearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT",
                "description": "格式: Bearer <access_token>(ch15 SimpleJWT 签发)",
            }
        }
    },
}

shopdemo/urls.py

from django.contrib import admin
from django.urls import path, include
from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularSwaggerView,
    SpectacularRedocView,
)

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", include("catalog.urls")),
  # OpenAPI 文档(开发期开启,生产见 14.8)
    path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
    path("api/schema/swagger-ui/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"),
    path("api/schema/redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"),
]

启动后访问:

路径内容
/api/schema/swagger-ui/Swagger UI 交互试调
/api/schema/redoc/Redoc 只读文档
/api/schema/OpenAPI JSON/YAML

14.3 自动生成与 Serializer 协同

drf-spectacular 默认从 SerializerViewSet@action 推断 schema。ch13 的 Serializer 即文档单一真相源:

# catalog/serializers.py — 字段定义即 OpenAPI components
class ProductListSerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True)
    cover_thumb = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = ["id", "name", "slug", "price", "stock", "is_published", "category", "cover_thumb", "created_at"]
层级职责
DRF Serializer运行时校验与序列化
AutoSchema从 Serializer 生成 components/schemas
@extend_schema补充描述、示例、额外响应码

分页响应PageNumberPagination 自动生成 count / next / previous / results 结构;若前端 user-demo 需固定契约,可在自定义 Pagination 类加 schema 属性或在 @extend_schema 中声明包装 Serializer。


14.4 @extend_schema 详解

# catalog/views.py(节选)
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter, OpenApiExample

@extend_schema_view(
    list=extend_schema(
        tags=["products"], summary="商品分页列表",
        parameters=[
            OpenApiParameter("search", str, description="按名称/slug 搜索"),
            OpenApiParameter("page", int, description="页码"),
        ],
        responses={200: ProductListSerializer(many=True)},
    ),
    create=extend_schema(
        tags=["products"], summary="创建商品",
        request=ProductWriteSerializer,
        responses={201: ProductDetailSerializer, 400: None, 401: None},
        auth=["BearerAuth"],
    ),
)
class ProductViewSet(viewsets.ModelViewSet):
    # get_serializer_class 同 ch13 ...

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。