django学习第十三天--自定义中间件
jquery操作cookie
- 下载地址
http://plugins.jquery.com/cookie/
- 引入
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.cookie.js"></script>
- cookie操作
设置值:
$.cookie('the_cookie','the_value');
#设置7天有效期
$.cookie('the_cookie','the_value',{expires:7});
读取
$.cookie('the_cookie'); #通过键来取值
删除cookie
$.cookie('the_cookie',null); #通过传递null作为cookie的值即可
中间件
配置文件
项目主目录中的配置文件是django留给开发者使用的用户级别配置文件
实际上django有一个自己的默认全局配置文件
那么他们的关系如下
#django默认配置
from django.conf import global_settings
#用户级别配置
from django_middleware import settinigs
from django.conf import settings #中间人
#比如需要引入配置中的某个配置项settings.APPEND_SLASH,那么这样的引入的查找顺序是这样的,先去用户级别settings.py文件中找这个配置,如果没有找到,那么再去global_settings中去找默认配置
django请求生命周期
中间件用来对请求和响应做一些统一加工和处理的,比如对所有请求中的post请求做一个csrftoken认证,就用到了我们的'django.middleware.csrf.CsrfViewMiddleware',后面视图中能够使用request.session做一个session相关操作,这个request.session的功能就是在这个中间件中加工好的'django.contrib.sessions.middleware.SessionMiddleware'
自定义中间件
- 登录认证、权限认证、频率访问限制、请求数据统计等等...
- 自定义中间的步骤
1.应用文件夹下面创建一个文件夹,名字随便起,比如叫作mymiddleware
2.在mymiddleware文件夹下面创建一个py文件,名称随意,比如叫做middlewares.py
3.在middlewares.py文件中写上如下内容
from django.utils.deprecation import MiddlewareMixin
class LoginAuth(MiddlewareMixin):
def process_request(self,request):
print('xxx')
4.settings.py配置文件中写上如下内容
MIDDLEWARE = [
....
'应用名.中间文件夹.中间文件.类'
'app01.mymiddleware.middlewares.LoginAuth', #配置中间件类,告诉django,我写的这个自定义中间件,你帮我使用上,一般都是放到最后,不然上面几个中间件的相关功能就没办法使用上了。
#如果中间件功能不想用了,就注释掉它就行了。
#以上几步搞定后,所有请求都会触发我们的中间件类中的process_request方法。
]
- 登录认证中间示例
中间件代码如下
#登录认证中间件
class LoginAuth(MiddlewareMixin):
#/login/登录请求,应该正常放行,让他能获得login.html页面
#添加一个白名单,这样首页登录就不需要登录认证
white_list = ['/login/',]
def process_request(self,request):
print('请求来啦!!!')
#获取当前请求路径:request.path /login/
#如果当前请求路径在白名单里面,我们不进行登录认证
if not request.path in self.white_list:
is_login = request.session.get('is_login') #True
if not is_login:
return redirect('/login/')
#视图代码
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
#print('xxxxxx')
uname = request.POST.get('username')
if uname == 'root':
request.session['is_login'] = True
return redirect('/home/')#告诉浏览器向/home/发送get请求获取页面
else:
return redirect('/login/')
def home(request):
print('home')
return render(request,'home.html')
def index(request):
print('index')
return render(request,'index.html')
#执行步骤:如判断用户访问home页面,是否已经登录过了
第一次请求的时候,先是走的中间件process_request,login路径,在白名单里面,所以就不会走下面的判断,
实际后面会有个return None,就表示是正常返回,可以省略不用写,然后再去执行视图逻辑,获取到login页面,get请求获取login页面。
第二次填写数据发送post请求,又会走一遍process_request,正常返回后再去执行视图逻辑,后台获取发送来的数据,
设置session,然后重定向到home页面,重定向的时候又会走了一遍process_request,然后中间件会判断这个重定向的路径,最后再执行视图逻辑。
下次想直接访问home页面的时候,先是发送/home/请求,先走中间件process_request,判断当前的路径是不是在白名单里,
显然不在,然后执行下面的逻辑代码,获取到session中的键值对,如获取到了,return None,那么就会执行视图里面的逻辑,就直接执行home函数。
如没有获取到,那么直接在中间件代码里面直接就重定向到login页面。
中间件的五个方法
整个中间件的执行顺序
process_request从上到下,process_response从下到上
- 五个方法:process_request和process_response这个两个是重点
process_request(self,request) #请求
process_view(self,request,view_func,view_args,view_kwargs)#视图
process_template_response(self,request,response)#模板
process_exception(self,request,exception) #错误
process_response(self,request,response) #响应
每个方法的执行流程
- 1.process_request
class Md1(MiddlewareMixin):
def process_request(self,request):
print('MD1--process_request')
#当process_request返回时None,可以默认不写,那么才会继续执行后面的中间件的process_request,如果你是最后一个中间件,并且你返回的是None,那么逻辑会继续执行到我们的url路由控制器
#但是当process_request里面return的是一个HttpResponse对象,那么后面的中间件的process_request将不再执行,也不会走到url路由控制器
#return HttpResponse('中间件md1的逻辑,没有通过!!!')
class Md2(MiddlewareMixin):
def process_request(self,request):
print('MD1--process_request')
views.py代码
def home(request):
print('home')
return render(request,'home.html')
执行流程--中间件正常return None的情况:
MD1--process_request
MD2--process_request
home
执行流程--中间件Md1中响应回复对象的情况:
MD1--process_request
因为Md1中return的是响应对象,所以就不会再向下执行了,同时也不会去执行逻辑代码。
- 2.process_response
class Md1(MiddlewareMixin):
def process_request(self,request):
print('MD1--process_request')
def process_response(self,request,response):
:param request: 当前请求对象
:param response: 视图函数的响应对象
:return:
print('Md1--响应')
#可以对响应内容做统一处理,如加响应头
response['xx'] = 'oo'
print(response.content) #获取响应回复内容 #b'ok'
#注意,如果你写了process_response方法,那么这个方法必须return response
return response
class Md2(MiddlewareMixin):
def process_request(self,request,response):
print('MD2--process_request')
def process_response(self,request,response):
print('MD2--响应')
# if response.content != b'ok':
#如果process_response方法里面return了一个HttpResponse对象,那么这个对象会覆盖视图返回来的HttpResponse对象
#return HttpResponse('响应不OK!!!')
return response
views.py文件
def home(request):
print('home')
return render(request,'home.html')
#return HttpResponse('我是home响应')
执行流程 正常执行:
MD1--process_request #中间件请求从上至下
MD2--process_request
home #请求结束会后执行视图逻辑
MD2--process_response #中间响应从下至上
MD1--process_response
执行流程 中间件HttpResponse响应覆盖视图返回来的Httpresponse对象:
MD1--process_request #中间件请求从上至下
MD2--process_request
home #执行视图逻辑,响应我是home响应
MD2--process_response #中间件响应从下至上,覆盖视图响应对象响应不OK!!!
MD1--process_response
- 注意事项
当中间件1的process_request方法return的是一个HttpResponse,那么会执行中间件1的process_response方法,不会去执行中间件2的方法了
- 3.process_view(self,request,view_func,view_args,view_kwargs)
from django.shortcuts import render,redirect,HttpResponse
from django.utils.deprecation import MiddlewareMix
class Md1(MiddlewareMixin):
def process_request(self,request):
print('MD1--process_request')
def process_response(self,request,response):
print('MD1--process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print('MD1--process_view')
class Md2(MiddlewareMixin):
def process_request(self,request):
print('MD2--process_request')
def process_response(self,request,response):
:param request:
:param view_func: 此次请求要执行的视图函数对象
:param view_args: 要函数的参数
:param view_kwargs: 要函数的参数
:return:
print('MD2--process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print('MD2--process_view')
执行流程:
MD1--process_request #中间件请求从上至下
MD2--process_request
MD1--process_view #中间件视图从上至下
MD2--process_view
中间件2执行函数名称 home
home #逻辑视图
MD2--process_response #中间件响应 从下至上
MD1--process_response
-
process_view图解
-
4.process_exception(self,request,exception)
当视图函数出现错误或者异常时,自动触发的方法,能够捕获视图出现的错误,进行一些错误的统一处理
from django.shortcuts import render,redirect,HttpResponse
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
def process_request(self,request):
print('MD1--process_request')
def process_response(self,request,response):
print('MD1--process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print('MD1--process_view')
def process_exception(self,request,exception):
print('MD1--process_exception')
class Md2(MiddlewareMixin):
def process_request(self,request):
print('MD2--process_request')
def process_response(self,request,response):
print('MD2--process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print('MD2--process_view')
def process_exception(self,request,exception):
from django.core.exceptions import PermissionDenied
# print('>>>>>>', exception, type(exception))
# if isinstance(exception,PermissionDenied):
# return HttpResponse('权限不够!!!!!')
#>>>>>> 权限不够 <class 'django.core.exceptions.PermissionDenied'>
# >>>>>> 出错啦!!!
print('MD2--process_exception')
views.py代码
from django.core.exceptions import PermissionDenied #为了演示错误
def home(request):
print('home')
raise PermissionDenied('权限不够')
return render(request,'home.html')
执行流程:
MD1--process_request #中间件请求从上至下
MD2--process_request
MD1--process_view #中间件视图从上至下
MD2--process_view
home #逻辑视图
MD2--process_exception #中间件错误从下至上
MD1--process_exception
MD2--process_response #中间件响应从下至上
MD1--process_response
-
process_exception图解
-
5.process_template_response(self,request,reponse)
from django.shortcuts import render,redirect,HttpResponse
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
def process_request(self,request):
print('MD1--process_request')
def process_response(self,request,response):
print('MD1--process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print('MD1--process_view')
def process_exception(self,request,exception):
print('MD1--process_view')
def process_template_response(self,request,response):
print('MD1--process_template_response')
return response
class Md2(MiddlewareMixin):
def process_request(self,request):
print('MD2--process_requeust')
def process_response(self,request,response):
print('MD2--process_response')
def process_view(self,request,view_func,view_args,view_kwargs):
print('MD2--process_view')
def process_exception(self,request,exception):
print('MD2--process_exception')
def process_template_response(self,request,response):
print('MD2--process_template_response')
return response
views.py代码
def home(request):
print('home')
def render():
print('你好render')
return HttpResponse('你好response')
ret = HttpResponse('ojbk')
#必须给HttpResponse对象封装一个render属性等于一个render函数,才能触发中间件里面的process_template_response方法
ret.render = render
return ret
执行流程:
MD1--process_request #中间件请求从上至下
MD2--process_request
MD1--process_view #中间件视图从上至下
MD2--process_view
home #视图逻辑
MD2--process_template_response #中间件模板 从下至上
MD1--process_template_response
你好render #视图逻辑里面的render()函数中响应对象
MD2--process_response #中间件响应 从下至上
MD1--process_response
总结下中间件执行流程
请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,
就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,
将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,
那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。
process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,
process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。加入中间件3 的process_view方法返回了HttpResponse对象,
则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。
url路由系统补充---include路由分发和命名空间 namespace
- 1.创建app
python manage.py startapp app01
- 2.配置app,在settings.py文件中
INSTALLED_APPS = [
...
'app02',
]
路由分发步骤
- 1.在项目主目录下的urls.py(以后我们称之为总路由)文件中,写上如下内容
from django.conf.urls import url,inclue
from django.contrib import admin
#路由分发功能
urlpatterns = [
url(r'^admin/',admin.site.urls),
url(r'^app01/',include('app01.urls')),#include参数格式'应用名称.urls'
url(r'^app02/',include('appo2.urls')),
#/app01/index/ 先在总路由中匹配前面的路径,然后匹配到了,拿剩下的index/,去app01应用下面的urls.py文件进行路径匹配
]
- 2.在每个应用文件夹下面创建一个ursl.py文件,里面内容
from django.conf.urls import url,include
from app01 import views
urlpatterns = [
url(r'^index/',views.index),
]
问题,当两个应用中的url的别名相同了,使用反向解析的时候该怎么解决
app01的urls.py
from django.conf.urls import url,include
from app01 import views
urlpatterns = [
url(r'^index/',views.index),
url(r'^home/',views.home,name='home'),
]
app02下的urls.py
from django.conf.urls import url,include
from app02 import views
urlpatterns = [
url(r'^index/',views.index),
url(r'^home/',views.home,name='home'),
]
app01的views.py文件进行别名解析
def index(request):
print('app01>>>',reverse('home'))
return HttpResponse('app01-index')
app02的views.py文件进行别名解析
def index(request):
print('app02>>>',reverse('home'))
return HttpResponse('app02-index')
以上执行完后,发现别名冲突,导致反向解析出错了
解决办法,用命名空间
总路由写法
from django.conf.urls import url,include
from django.contrib import admin
#路由分发
urlpatterns = [
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02')),
]
app01视图写法
def index(request):
print('app01>>>',reverse('app01:home'))
return HttpResponse('app01-index')
app02视图写法
def index(request):
print('app02>>',reverse('app02:home'))
return HttpResponse('app02-index')
模板中使用
{% url 'app01:home' %}
路由分发如何设置首页
如果我们想通过输入http://127.0.0.1:8000/app01/,看到app01这个应用的首页,怎么办?就像现在输入一个http://127.0.0.1:8000来查看网站的首页,怎么办?
url(r'^$', views.index),#以空开头,还要以空结尾,写在项目的urls.py文件里面就是项目的首页,写在应用文件夹里面的urls.py文件中,那就是app01的首页
整个完整请求-中间件-后台逻辑处理的过程
-------------------------------------------
个性签名:代码过万,键盘敲烂!!!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!