You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用装饰器的情况下自定义Django Rest Framework文档?

无需过度依赖装饰器的DRF文档定制方案

1. 把文档定义内聚到Serializer中

将字段的说明、约束等文档信息直接写在Serializer的字段定义或Meta类里,drf-pectacular会自动读取这些信息生成文档,无需在View层加装饰器,让数据结构和文档说明保持统一。

示例代码:

from rest_framework import serializers

class BookSerializer(serializers.ModelSerializer):
    author_name = serializers.CharField(
        source="author.name",
        help_text="书籍作者的姓名,关联自Author模型的name字段"
    )
    publication_year = serializers.IntegerField(
        help_text="书籍出版年份,范围为1900-2024"
    )

    class Meta:
        model = Book
        fields = ["id", "title", "author_name", "publication_year"]
        extra_kwargs = {
            "title": {
                "help_text": "书籍的标题,最长不超过100个字符"
            }
        }

2. 封装通用ViewSet基类统一配置文档

如果多个ViewSet有重复的文档规则(比如通用响应状态码、分页说明),抽离出一个基类ViewSet,把通用的文档配置放在基类的方法里,子类直接继承即可,避免重复编写装饰器。

示例代码:

from rest_framework.viewsets import ModelViewSet
from drf_spectacular.utils import extend_schema

class BaseModelViewSet(ModelViewSet):
    @extend_schema(
        responses={
            200: "成功返回数据列表/详情",
            401: "未授权,需要登录",
            403: "无权限访问该资源",
            404: "资源不存在"
        },
        pagination_class=None  # 项目统一分页类可在此指定
    )
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

    @extend_schema(
        responses={
            200: "成功返回资源详情",
            401: "未授权",
            403: "无权限",
            404: "资源不存在"
        }
    )
    def retrieve(self, request, *args, **kwargs):
        return super().retrieve(request, *args, **kwargs)

# 子类无需重复写文档装饰器,专注业务逻辑
class BookViewSet(BaseModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

3. 全局定制SchemaGenerator统一文档规则

通过drf-pectacular的全局配置和自定义SchemaGenerator,统一处理文档的标签、默认响应、安全方案等规则,不用在每个View里单独配置。

首先在settings.py中配置:

SPECTACULAR_SETTINGS = {
    'TITLE': '你的项目API文档',
    'DESCRIPTION': '基于Django Rest Framework构建的API服务',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
    'DEFAULT_GENERATOR_CLASS': 'your_project.schema.CustomSchemaGenerator',
    'SECURITY': [{'Bearer': []}],  # 全局JWT认证配置
    'TAGS': [
        {'name': '书籍管理', 'description': '书籍相关的CRUD操作'},
        {'name': '用户管理', 'description': '用户注册、登录、权限管理'}
    ]
}

然后自定义CustomSchemaGenerator:

from drf_spectacular.generators import SchemaGenerator

class CustomSchemaGenerator(SchemaGenerator):
    def get_tags(self, path, method):
        # 自动根据ViewSet关联的Model分配标签
        view = self._get_view(path, method)
        if hasattr(view, 'queryset'):
            model_name = view.queryset.model._meta.verbose_name_plural
            return [model_name]
        return super().get_tags(path, method)

    def get_operation(self, path, method):
        operation = super().get_operation(path, method)
        # 全局添加默认的400参数错误响应
        operation['responses'].setdefault('400', {'description': '请求参数错误'})
        return operation

4. 利用action参数配置自定义动作文档

对于ViewSet的自定义action,无需单独加@extend_schema装饰器,直接通过action装饰器的参数配置文档信息,或在ViewSet初始化时统一配置。

示例代码:

from rest_framework.decorators import action

class BookViewSet(BaseModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    # 通过action参数配置文档
    @action(
        detail=True,
        methods=['post'],
        serializer_class=BookReviewSerializer,
        help_text="为指定书籍添加评论"
    )
    def add_review(self, request, pk=None):
        book = self.get_object()
        # 业务逻辑实现
        return Response({"status": "success"})

    # 或者在初始化时统一补充action文档
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.action_map['add_review']['description'] = "提交评论内容和1-5分的评分,为书籍添加用户评论"

5. 从Model层继承文档信息

DRF和drf-pectacular会自动读取Model字段的verbose_name和help_text,所以直接在Model层定义这些信息,Serializer会自动继承,进而生成对应的API文档,无需额外装饰器。

示例代码:

from django.db import models

class Book(models.Model):
    title = models.CharField(
        max_length=100,
        verbose_name="书籍标题",
        help_text="书籍的正式标题,最长不超过100个字符"
    )
    publication_year = models.IntegerField(
        verbose_name="出版年份",
        help_text="书籍的出版年份,必须为1900年之后的整数"
    )
    author = models.ForeignKey(
        Author,
        on_delete=models.CASCADE,
        verbose_name="作者",
        help_text="关联的作者模型"
    )

    class Meta:
        verbose_name = "书籍"
        verbose_name_plural = "书籍管理"

内容的提问来源于stack exchange,提问作者rowsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:23:21