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