DRF 内容协商 #

一、内容协商概述 #

1.1 什么是内容协商 #

内容协商是客户端和服务器协商数据格式的过程:

text
客户端请求 → Accept头 → 服务器选择渲染器 → 返回相应格式

1.2 核心组件 #

组件 说明
渲染器 序列化响应数据
解析器 解析请求数据
内容协商 选择合适的渲染器/解析器

二、渲染器 #

2.1 内置渲染器 #

python
from rest_framework.renderers import (
    JSONRenderer,           # JSON格式
    BrowsableAPIRenderer,   # 可视化API
    TemplateHTMLRenderer,   # HTML模板
    StaticHTMLRenderer,     # 静态HTML
)

2.2 全局配置 #

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

2.3 视图级别配置 #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    renderer_classes = [JSONRenderer, BrowsableAPIRenderer]

2.4 自定义渲染器 #

python
from rest_framework.renderers import BaseRenderer
import csv
from io import StringIO

class CSVRenderer(BaseRenderer):
    media_type = 'text/csv'
    format = 'csv'
    
    def render(self, data, media_type=None, renderer_context=None):
        if not isinstance(data, list):
            data = [data]
        
        if not data:
            return ''
        
        output = StringIO()
        writer = csv.DictWriter(output, fieldnames=data[0].keys())
        writer.writeheader()
        writer.writerows(data)
        
        return output.getvalue()

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    renderer_classes = [JSONRenderer, CSVRenderer]

2.5 请求格式 #

text
GET /api/articles/           # 默认JSON
GET /api/articles/?format=csv  # CSV格式
GET /api/articles.csv        # CSV格式(需配置)
Accept: text/csv             # CSV格式

三、解析器 #

3.1 内置解析器 #

python
from rest_framework.parsers import (
    JSONParser,          # JSON
    FormParser,          # 表单
    MultiPartParser,     # 文件上传
    FileUploadParser,    # 文件上传
)

3.2 全局配置 #

python
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],
}

3.3 视图级别配置 #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    parser_classes = [JSONParser, MultiPartParser]

3.4 自定义解析器 #

python
from rest_framework.parsers import BaseParser
import xml.etree.ElementTree as ET

class XMLParser(BaseParser):
    media_type = 'application/xml'
    
    def parse(self, stream, media_type=None, parser_context=None):
        data = stream.read()
        root = ET.fromstring(data)
        
        result = {}
        for child in root:
            result[child.tag] = child.text
        
        return result

四、格式后缀 #

4.1 启用格式后缀 #

python
from rest_framework.urlpatterns import format_suffix_patterns
from .views import ArticleViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet)

urlpatterns = format_suffix_patterns(router.urls)

4.2 访问方式 #

text
GET /api/articles.json
GET /api/articles.csv
GET /api/articles.api

五、总结 #

本章学习了DRF内容协商:

  • 渲染器:序列化响应数据
  • 解析器:解析请求数据
  • 自定义格式:创建自定义渲染器/解析器
  • 格式后缀:URL指定格式

内容协商让API支持多种数据格式!

最后更新:2026-03-28