DRF对Django请求响应做了技术升级
Django视图是用来处理请求和响应的,Django默认是按Form和Template来设计的,如果要处理以JSON格式为主的RESTful API,那么就需要对Django请求和响应的处理代码进行优化改造,本文就来介绍DRF在这一部分的技术升级。
Request
DRF把Django的HttpRequest扩展成了Request:

其中最核心的属性是request.data,它和request.POST的区别如下:
request.POST # 只处理表单(Form)数据,只支持POST方法
request.data # 处理任何数据,支持POST、PUT、PATCH方法
Response
DRF的Response继承自Django的django.template.response.SimpleTemplateResponse:

Response可以根据客户端的请求render合适的content type:
return Response(data)
我摘取了rendered_content()函数的代码:
@property
def rendered_content(self):
renderer = getattr(self, 'accepted_renderer', None)
accepted_media_type = getattr(self, 'accepted_media_type', None)
context = getattr(self, 'renderer_context', None)
assert renderer, ".accepted_renderer not set on Response"
assert accepted_media_type, ".accepted_media_type not set on Response"
assert context is not None, ".renderer_context not set on Response"
context['response'] = self
media_type = renderer.media_type
charset = renderer.charset
content_type = self.content_type
if content_type is None and charset is not None:
content_type = "{}; charset={}".format(media_type, charset)
elif content_type is None:
content_type = media_type
self['Content-Type'] = content_type
ret = renderer.render(self.data, accepted_media_type, context)
if isinstance(ret, str):
assert charset, (
'renderer returned unicode, and did not specify '
'a charset value.'
)
return ret.encode(charset)
if not ret:
del self['Content-Type']
return ret
Status codes
如果在代码中直接写数字形式的状态码如400,是不容易阅读的,于是DRF提供了标识符如HTTP_400_BAD_REQUEST来替代。我列一些常见的状态码标识符:
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_204_NO_CONTENT = 204
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
全部的状态码标识符可以在rest_framework.status模块中看到。
@api_view和APIView
DRF对API视图做了2个封装:
@api_view用于函数视图。APIView用于类视图。
它们提供了一些新功能,比如:
- 检查请求是
Request对象 - 添加上下文到
Response对象 - 返回请求错误如
405 Method Not Allowed - 当
request.data格式有误时,抛出ParseError异常
改造views.py
接着就用上面这几个新实现对我们之前写的snippets/views.py进行改造:
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
@api_view(['GET', 'POST'])
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = SnippetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
Retrieve, update or delete a code snippet.
"""
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = SnippetSerializer(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
改动点有这些,添加了@api_view,如:
@api_view(['GET', 'POST'])
使用了状态码标识符,如:
status.HTTP_404_NOT_FOUND
使用request.data替代了 data = JSONParser().parse(request),如:
serializer = SnippetSerializer(data=request.data)
使用Response()替代了JsonResponse(),如:
return Response(serializer.data, status=status.HTTP_201_CREATED)
request.data和Response()能根据请求的JSON自动处理content type。
添加后缀格式(可选)
既然DRF能自动处理content type,那么也可以给URL指定具体的后缀格式,比如http://example.com/api/items/4.json。具体添加步骤是,先给view增加1个可选参数format:
def snippet_list(request, format=None):
def snippet_detail(request, pk, format=None):
再更新snippets/urls.py,添加format_suffix_patterns:
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>', views.snippet_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)
这并不是必须的,实际上也无需这么做。
测试API
http http://127.0.0.1:8000/snippets/
HTTP/1.1 200 OK
...
[
{
"id": 1,
"title": "",
"code": "foo = \"bar\"\n",
"linenos": false,
"language": "python",
"style": "friendly"
},
{
"id": 2,
"title": "",
"code": "print(\"hello, world\")\n",
"linenos": false,
"language": "python",
"style": "friendly"
}
]
跟之前的结果一样。再分别用form和json试试:
# POST using form data
http --form POST http://127.0.0.1:8000/snippets/ code="print(123)"
{
"id": 3,
"title": "",
"code": "print(123)",
"linenos": false,
"language": "python",
"style": "friendly"
}
# POST using JSON
http --json POST http://127.0.0.1:8000/snippets/ code="print(456)"
{
"id": 4,
"title": "",
"code": "print(456)",
"linenos": false,
"language": "python",
"style": "friendly"
}
API文档
DRF提供了可视化的API HTML文档,把API URL在浏览器中打开即可看到:

东方说
最近测试开发和业务测试的话题频频出现在TesterHome论坛上,讨论激烈,我觉得从公司的角度来说,只会关注员工的产出有没有给公司带来价值,无论技术多厉害,不能创造价值终究是会优先被裁的。从个人的角度来说,只会业务测试的出路肯定是会越来越窄的,努力提高技术,辅助业务测试,同时提升效率,才是更好的发展方向。千万要谨慎选择只做纯测试工具,要依托于业务,让技术落地,在业务中发挥技术的价值,产生从业务到技术,从技术到业务的良好循环。当然,会技术是个大前提,对技术的学习不能停,比如Django REST framework。
参考资料:
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/
DRF对Django请求响应做了技术升级的更多相关文章
- Django请求响应对象
请求与响应对象 HttpRequest HttpRequest存储了客户请求的相关参数和一些查询方法. path 请求页面的全路径,不包括域名-例如, "/hello/". met ...
- Django请求,响应,ajax以及CSRF问题
二.request对象常用属性: Attribute Description path 请求页面的全路径,不包括域名端口参数.例如: /users/index method 一个全大写的字符串,表示请 ...
- Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)
一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...
- DRF的请求响应组件
目录 DRF的请求响应组件 请求模块(request) 概念 request源码简单分析 响应模块(response) 概念 使用方法 response源码简单分析: 解析模块(parse) 概念 使 ...
- Django(十一)请求生命周期之响应内容(请求/响应 头/体)
https://www.cnblogs.com/renpingsheng/p/7534897.html Django请求生命周期之响应内容 http提交数据的方式有"post",& ...
- Django请求生命周期之响应内容
Django请求生命周期: 1.发送http请求2.服务器接受,根据请求头中的url在路由关系表中进行匹配(从上到下)3.匹配成功后,执行指定的views函数 URL -> 函数 ==>F ...
- 第一篇 Flask基础篇之(配置文件,路由系统,模板,请求响应,session&cookie)
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- Django(35)Django请求生命周期分析(超详细)
Django请求生命周期分析 1.客户端发送请求 在浏览器输入url地址,例如www.baidu.com,浏览器会自动补全协议(http),变为http://www.baidu.com,现在部分网站都 ...
- HTTP协议请求响应过程和HTTPS工作原理
HTTP协议 HTTP协议主要应用是在服务器和客户端之间,客户端接受超文本. 服务器按照一定规则,发送到客户端(一般是浏览器)的传送通信协议.与之类似的还有文件传送协议(file transfer p ...
随机推荐
- 闭关苦修半年,最终靠着这份面试题,我成功拿到了阿里的offer!
前言 我大概我是从去年12月份开始看书学习,到今年的6月份,一直学到看大家的面经基本上百分之90以上都会,我就在5月份开始投简历,边面试边补充基础知识等.也是有些辛苦.终于是在前不久拿到了阿里的off ...
- PVE 下的虚拟机磁盘扩容
扩容背景:一台测试机磁盘不足,需要扩容: /dev/mapper/centos-root 40G 40G 20K 100% / 先到PVE网页上对需要扩容的机器扩容,这里新建20G示例: 另外之前也分 ...
- 关于Folx一些使用方面的问题详细解答
Folx作为一款的专业的Mac系统文件下载工具,相信大家或多或少都对它的主打功能,如智能限速.制定计划任务.直链文件下载等功能有所了解,但是对于它的一些相对少见.冷门的功能,却不太熟悉. 下面小编将通 ...
- ABBYY FineReader 15高级转换功能详解
ABBYY FineReader 15(Windows系统)OCR文字识别软件拥有强大的OCR项目功能,能帮助用户检查识别区域.验证识别出的文本.预处理图像以提高 OCR精确性等等.其强大的OCR微调 ...
- 如何用ABBYY FineReader提取图片中的文字
作为OCR文字识别软件中的佼佼者,可能大家对于ABBYY FineReader的使用还不熟练,没关系,今天小编就为大家演示,如何用ABBYY FineReader这款文字识别软件,将一张截图中的文字识 ...
- Linux-CentOS7下安装Oracle11g
简述: 本文操作环境采用CentOS7 Linux安装Oracle11g与Windows区别较大,在Linux下需要创建用户以及用户组来供Oracle使用 Windows可以直接图形化界面从第一步到最 ...
- python3时间函数
上一篇是生成测试报告的代码,如果重复运行测试报告名称相同会不停的覆盖,之前的测试报告也会丢失,无法追溯之前的问题.那么如何解决这个问题了呢? 首先想到的是用随机函数取随机名称,一旦生成的报告较多时,无 ...
- java编写规范及注意事项
java编写规范及注意事项 1.注释 常见注释有三种 // /**/ /****/ 如何才能写出漂亮的注释呢,注释的目的就是为了使你的代码让人更容易理解和维护,写一手好的注释是一个优秀码农的基本 ...
- 深度学习(一):Python神经网络——手写数字识别
声明:本文章为阅读书籍<Python神经网络编程>而来,代码与书中略有差异,书籍封面: 源码 若要本地运行,请更改源码中图片与数据集的位置,环境为 Python3.6x. 1 import ...
- 有了Git这个操作,我再也不怕代码混乱了!
大家好,今天的文章我们来介绍git当中一个非常常用的功能--储藏. 大家在协同开发的时候应该都有这样的经历,有的时候我们的功能开发了一半,因为某些原因我们想要checkout到其他的分支上查看代码或者 ...