DRF 默认不启用XMLRenderer,需手动在DEFAULT_RENDERER_CLASSES中添加;XMLRenderer要求数据为字典且顶层键作根元素,列表须包装为字典;自定义根名需子类化XMLRenderer。
DRF 默认只注册 JSONRenderer,XMLRenderer 虽然内置但未自动加入 DEFAULT_RENDERER_CLASSES。直接返回 XML 会触发 NotAcceptable (406) 错误,浏览器或 curl -H "Accept: application/xml" 都拿不到 XML 响应。
推荐在全局设置中添加,避免每个视图重复声明。注意顺序:XML 渲染器需放在 JSON 之后,否则 Accept: */* 可能优先匹配 XML(部分客户端行为不一致)。
settings.py 中修改 REST_FRAMEWORK 配置:REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.XMLRenderer', # ← 显式加入
],
}from rest_framework.renderers import XMLRendererclass MyAPIView(APIView): renderer_classes = [XMLRenderer, JSONRenderer] # 顺序影响 content-negotiation def get(self, request): return Response({'name': 'Alice', 'age': 30})
XMLRenderer 不支持任意嵌套对象或列表顶层渲染——它要求数据是字典,且顶层键将成为根元素名。传入 [{'id': 1}, {'id': 2}] 会报 TypeError: object of type 'list' has no len()。
renderer_context 或自定义)Response([obj1, obj2]) → 必须改为 Response({'users': [obj1, obj2]})
None 时,XML 中该元素仍会出现但为空标签(),不会被跳过DRF 的 XMLRenderer 不提供开箱即用的命名空间或根名覆盖接口,但可通过子类轻量扩展:
from rest_framework.renderers import XMLRendererclass CustomXMLRenderer(XMLRenderer): root_tag_name = 'response' # 可设为类属性或从 renderer_context 动态取
def render(self, data, accepted_media_type=None, renderer_context=None): if data and isinstance(data, dict) and 'root_tag_name' in renderer_context: self.root_tag_name = renderer_context['root_tag_name'] return super().render(data, accepted_media_type, renderer_context)
return Response(data, renderer_context={'root_tag_name': 'book_list'})
djangorestframework-xml 的增强版)renderer_classes 中替换原 XMLRenderer
XML 渲染真正麻烦的不是配置,而是数据结构必须严格适配其字典+单根约束;很多开发者卡在 Response([...]) 上,却没意识到错误信息里那句 Expected a 已经说得很清楚了。dict, but got list