如何用DRF编写可同时返回HTML与JSON格式的API?
基于DRF实现同一接口返回HTML/JSON格式的方案
不需要单独为网站和客户端编写两套视图,利用DRF自带的**内容协商(Content Negotiation)**机制,就能让同一接口根据请求的Accept头自动返回对应格式,这是更优的实现方案。
核心实现步骤
- 配置全局渲染器
在项目的settings.py中,为DRF配置同时支持JSON和HTML的默认渲染器:
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.TemplateHTMLRenderer', ] }
- 编写多格式兼容的API视图
在视图中指定HTML模板名称,DRF会自动根据请求头选择渲染方式:
from rest_framework.views import APIView from rest_framework.response import Response class HomeView(APIView): # 可显式指定渲染器(也可依赖全局配置) renderer_classes = ['rest_framework.renderers.TemplateHTMLRenderer', 'rest_framework.renderers.JSONRenderer'] template_name = 'home.html' # 对应HTML模板路径 def get(self, request): # 准备统一的业务数据 data = { 'site_name': '我的站点', 'notices': [ {'id': 1, 'content': 'DRF内容协商测试完成'}, {'id': 2, 'content': '新版本已上线'} ] } # 直接返回数据,DRF自动处理格式转换 return Response(data)
- 编写HTML模板
在项目templates目录下创建对应的模板文件home.html,用Django模板语法渲染数据:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>{{ site_name }}</title> </head> <body> <h1>欢迎来到{{ site_name }}</h1> <div class="notice-list"> <h3>最新通知</h3> {% for notice in notices %} <p>{{ notice.content }}</p> {% endfor %} </div> </body> </html>
进阶差异化处理
如果需要针对不同格式做自定义逻辑,可通过request.accepted_renderer判断当前渲染器:
def get(self, request): data = {'base_info': '通用数据'} # 为HTML请求添加网页专属数据 if isinstance(request.accepted_renderer, rest_framework.renderers.TemplateHTMLRenderer): data['web_extra'] = '仅网页端显示的额外内容' return Response(data)
效果说明
- 浏览器访问时,请求头包含
text/html,DRF会渲染HTML模板返回完整页面。 - 移动/桌面客户端请求时,只需设置
Accept: application/json,接口将直接返回JSON格式数据。
内容的提问来源于stack exchange,提问作者bl4z3rr666
相关产品推荐
相关产品推荐

