我们首先来看django的请求生命周期
-先进入实现了wsgi协议的web服务器----》进入django---》中间件---》路由---》视图---》取模板,取数据,用数据渲染模板---》返回模板的字符串---》在浏览器上看到页面了
这里我们不妨来看看wsgire协议和CGI协议
CGI是比较原始的开发动态网站的方式。你可以想象一下,一个网站的动态内容肯定是程序生成的,光是静态的html页面无法达到这个效果。那么,这个程序就需要接受客户端的请求,然后进行相应处理,再返回给客户端,客户端和服务端的通信当然是通过HTTP协议。然后我们会发现,这个程序在处理客户端请求的时候,大部分时候会进行很多重复的工作,比如说HTTP请求的解析。也就是说,你的程序需要解析HTTP请求,我的程序也需要解析。于是为了DRY原则,Web服务器诞生了。(以下所说的都是CGI的工作模式)
于是Web服务器可以解析这个HTTP请求,然后把这个请求的各种参数写进进程的环境变量,比如REQUEST_METHOD,PATH_INFO之类的。之后呢,服务器会调用相应的程序来处理这个请求,这个程序也就是我们所要写的CGI程序了。它会负责生成动态内容,然后返回给服务器,再由服务器转交给客户端。服务器和CGI程序之间通信,一般是通过进程的环境变量和管道。这样做虽然很清晰,但缺点就是每次有请求,服务器都会fork and exec,每次都会有一个新的进程产生,开销还是比较大的。原因在与CGI程序是一个独立的程序,它是可以独立运行的(在提供HTTP请求的情况下),它可以用几乎所有语言来写,包括perl,c,lua,python等等。所以对于一个程序,服务器只能以fork and exec的方式来调用它了。
WSGI是Web Server Gateway Interface的缩写。以层的角度来看,WSGI所在层的位置低于CGI。但与CGI不同的是WSGI具有很强的伸缩性且能运行于多线程或多进程的环境下,这是因为WSGI只是一份标准并没有定义如何去实现。实际上WSGI并非CGI,因为其位于web应用程序与web服务器之间,而web服务器可以是CGI,mod_python(注:现通常使用mod_wsgi代替),FastCGI或者是一个定义了WSGI标准的web服务器就像python标准库提供的独立WSGI服务器称为wsgiref。
WSGI里的组件分为『Server』,『Middleware』和『Application』三种,其中的『Middleware』是『设计模式』里的Decorator(装饰器)。
WSGI规范在PEP-333里讲得很详细:PEP 0333 -- Python Web Server Gateway Interface v1.0 ,但我觉得比理解规范更重要的,是理解其设计目的和工作原理。
WSGI规范写得有点绕,之所以绕, 主要原因可能是没有用『类型提示(Type Hints)』,如果用强类型OOP语言的那种『Interface』和『UML』来解释会清晰很多。
实现了wsgi 协议对应的web服务器就是uwsgi,类似Java中的tomcat 。有兴趣的话可以读一下tomcat原理https://blog.csdn.net/qq_38977097/article/details/81089172
CBV 源码分析
原生django的视图层可以分为两类 FBV和CBV,由于djangorestframework只能够由FBV完成,所以简单来看一下FBV的源码。
在FBV视图里面 ,我们的路由是类加as_view(),但是我们写的类并没有这个属性或方法 ,其实是用了父类(view)的
as_view的方法,
不难看出这就是一个闭包函数,传参给view函数,这时候会走view里面的self.dispatch方法,由于对象没有,只能够走父类(view)的dispatch方法
dispatch方法只是利用了反射请求方法来分发函数,至此我们对CBV源码有了一个简单认识。看懂这个将对我们理解后面的drf有极大地帮助。
restful规范
- REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
- REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
- 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
下面我们逐条来分析一下restful规范的设计
1 API与用户的通信协议,总是使用HTTPs协议。
2 域名有区分
-https://api.example.com
-https://example.org/api/
3 版本
可以放在路径中
可以放在请求头中
4 路径,视网络上任何东西都是资源,均使用名词表示
https://api.example.com/v1/zoos
5 通过method 区分是什么操作
get表示获取
post表示新增
delete表示删除
patch/put 表示修改
6 过滤,通过在url上传参的形式传递搜索条件
7 状态码
{"status_code":100}
8 错误处理,应返回错误信息
{"status_code":100,'msg':'登录成功'}
{"status_code":101,'msg':'用户名错误'}
9 返回结果,针对不同操作,服务器向用户返回的结果
get获取所有资源/get获取一个资源
127.0.0.1/api/vi/books 获取所有图书
{"status_code":100,'msg':'获取成功',data:[{},{}]}
127.0.0.1/api/vi/books/3 获取id为3的图书
{"status_code":100,'msg':'获取成功',data:{name:xx,....}}
新增数据,把新增的数据再返回
修改了数据,返回完整的资源对象
删除数据,返回一个空文档
10 返回结果中提供链接
{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}
基于原生django开发restful的接口
from django.views import View from app01 import models class APIView(View): def dispatch(self, request, *args, **kwargs): #写一些频率控制的东西 ret = super().dispatch(request, *args, **kwargs) return ret class Test(APIView): # http_method_names=['get'] def get(self,request, *args, **kwargs): return HttpResponse('ok')
djangorestframework
安装下载:pip install djangorestframework
from rest_framework.views import APIView class Books(APIView): def get(self,request): #request是被封装后的request,原生的request在request._request #如果想用原生requset中的属性,还是原来的用法,因为Request重写了__getattr__方法 # 原生django只能处理urlencoded和formdata编码,如果是json格式,原生django是不能处理的,需要自己从body中取出来自行处理 # request.data 不管前端传数据的编码格式是urlencoded,formdata或者是json,都从里面取值 # request.data #request.query_params 是原来django原生的GET中的数据 #self.FILES 就是上传的文件 dic={'name':'lqz','age':30,'height':178,'wife':['liuyifei','dilireba','egon']} return JsonResponse(dic)
#在settings.py文件中添加rest_framework,这就是django的一个app。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'rest_framework' ]
我们对drf的源码分析,首先我们定义一个类,这个类继承的事APIView
继承了APIView 之后:
1 所有的请求都没有csrf的认证了
2 在APIView中as_view本质还是调用了父类的as_view(View的as_view)
3 as_view中调用dispatch -----》这个dispatch是APIView的dispatch
APIVIew的dispatch方法:
1 对原生request对象做了一层包装(面向对象的封装),以后再用的request对象都新的request对象
2 在APIView中self.initial(request, *args, **kwargs),里面有频率控制,权限控制和认证相关
3 根据请求方法执行咱们写的视图类中的相应方法
这个时候视图类中方法的request对象,已经变成了封装后的request
Request类:
1 原生的request是self._request
2 取以post形式提交的数据,从request.data中取(urlencoded,formdata,json格式)
3 query_params 就是原生request的GET的数据
4 上传的文件是从FILES中取
5 (重点)其他的属性,直接request.属性名(因为重写了__getattr__方法)