Django:中间件
一、Django中间件
django默认自带七个中间件,还支持用户自定义中间件
1.作用:全局的处理:会对所有的资源请求,所有的返回方式,所有的路由到视图的跳转、所有视图层的异常进行处理。
-
使用场景:当想用全局功能的时候
-
1:限制访问频率校验:这种功能应该在中间件中编写,减少对django后端资源的浪费
-
2:用户权限校验:(在web领域:权限就是网址)登录成功之后,每次请求来的时候,在请求中辨别出用户权限,如果符合则可以访问某些功能
2.Django流程图
二、自定义中间件
由于django自带的一些中间件之间是有逻辑联系的,所有自定义的中间件最好注册在最开头或者结尾,不要插在七个自定义的中间件中间
1.创建存储自定义中间件代码的py文件或者目录
2.参考自带中间件的代码编写类并继承MiddlewareMixin
3.在类中编写五个可以自定义中间件的方法
- 需要掌握的
process_request
process_response
- 需要了解的
process_view
process_exception
process_template_response
4.在配置文件中需要注册才能生效
三、中间件执行流程
1.request和response通过中间件的顺序
2.process_request和process_response方法
-
process_request
1.请求来的时候会依次经过每一个在settings中注册了的中间件里面的该方法,在注册顺序从上往下依次执行,每个中间件中的process_request,如果没有process_request方法则跳过
2.如果方法自己返回了HttpReponse对象,那么不再往后执行,直接原路返回给前端
class MyMiddleware1(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
print("我是中间件1的view")
-
process_response
1.响应走的时候,会从下往上一次经过每一个注册了的中间件里面的方法,如果没有则直接跳过
2.该方法必须要有两个形参
request
和response
,返回形参response,也可以返回自己定义的
如果在执行process_response方法的时候,直接返回了HttpReponse对象,那么会原路返回执行process_response
四、django中间件三个了解的方法
- 需要了解的
process_view
process_exception
process_template_response
1.process_view
触发时间:路由匹配成功之后,执行视图函数/类之前自动触发(顺序同process_request,在注册文件中从上往下依次触发)
class MyMiddleware01(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
print("from MyMiddleware0101 process_view")
2.process_exception
触发时间:执行视图函数/类,报错的之后自动触发,执行顺序同process_response从下往上
形参exception是异常信息
class MyMiddleware1(MiddlewareMixin):
def process_exception(self, request, exception):
print("from MyMiddleware01 process_exception")
3.process_template_response
只要形参中有response的都需要返回
触发时间:当视图函数/类中返回一个HttpResponse对象,并且对应一个方法的时候自动触发(执行顺序同process_response从下往上)
五、基于django中间件的插拔式设计
django中间件管理功能的方式:
将各个功能制作成配置文件的字符串形式,如果想拥有该功能就编写对应的字符串,如果不想使用该功能则注释掉对应的字符串
1.内置模块importlib
作用:通过传一个字符串形式的路径,将字符串导入模块
原理:通过字符串按.
从右往左切一个,前面是路径,最后一个是py文件,从而导入模块
只要能变成字符串,就可以和用户交互
缺点:字符串的结尾,最小单位只能是py文件级别,不能是py文件中的变量名
import importlib
s1 = 'bbb.b' # aaa.bbb.ccc.b
res = importlib.import_module(s1) # from aaa.bbb.ccc import b
print(res) # <module 'bbb.b' from 'D:\\pythonProject03\\djangomiddle\\bbb\\b.py'>
2.插拔式设计
- 需求与分析:编写一个消息通知功能,通过微信、qq、邮箱,点一个按钮
(1)方式一:函数封装版本
通过每个函数来进行封装发送消息的功能
def send_qq(msg):
print('来自于qq的消息>>>:%s'%msg)
def send_weixin(msg):
print('来自于weixin的消息>>>:%s'%msg)
def send_email(msg):
print('来自于email的消息>>>:%s'%msg)
(2)方式二:基于django中间件的功能设计
多态性:不同的对象具有相同功能,应该有相同名字的方法
- 定义三个py文件存储不同的类
# qq.py
class Qq(object):
def __init__(self):
pass # 模拟发送qq之前需要做的准备操作
def send_msg(self, content):
print('来自于qq的消息>>>:%s'%content)
# Weixin.py
class Weixin(object):
def __init__(self):
pass # 模拟发送微信之前需要做的准备操作
def send_msg(self, content):
print('来自于Weixin的消息>>>:%s' % content)
# Email.py
class Email(object):
def __init__(self):
pass # 模拟发送email之前需要做的准备操作
def send_msg(self, content):
print('来自于email的消息>>>:%s' % content)
-
在notify目录的
__init__.py
文件中,应该导入三个模块中的类,运用 importlib模块拿到文件名的字符串与类的字符串,最后通过反射获取字符串对应的类产生对象,调用发送消息的方法
from settings import NOTIFY_LIST
import importlib
def send_all(content):
for full_path in NOTIFY_LIST: # path='notify.email.Email'
module_path, class_str_name = full_path.rsplit('.', maxsplit=1) # 'notify.email' 'Email'
# 1.利用字符串导入模块 拿到模块名
module_name = importlib.import_module(module_path) # from notify import email
# 2.利用反射从模块中获取字符串对应的类名
class_name = getattr(module_name, class_str_name) # Email
# 3.利用类名加括号产生对象
obj = class_name()
# 4.对象调用发送消息的方法
obj.send_msg(content)
- settings.py文件中注册发送消息的类
NOTIFY_LIST = [
'notify.email.Email',
'notify.qq.Qq',
'notify.weixin.Weixin',
]
六、cookie与session简介
1.Http协议四大特性
2.cookie与session简介
(1)历史发展
早期:早期的cookie很不安全,可以通过查看浏览器中的文件就可以查看到用户名和密码
现在:当第一次输入用户名和密码之后,服务端会返回一个随机字符串,在服务端内部已经记录了随机字符串和用户的对应关系,当发送请求的时候,就可以进行比对随机字符串。
(2)概念
session:用户登录的时候返回一个随机字符串,随机字符串保存在服务端上和用户状态相关的数据就叫session
cookie:保存在客户端上和用户状态相关的数据叫做cookie
名称 | 存储位置 |
---|---|
Cookie | 客户端/浏览器 |
Session | 服务端 |
- session的工作需要依赖于cookie,所有与用户状态相关的操作都需要依赖于cookie
(3)补充
-
谁拿到cookie的用户数据,通过cookie请求服务端,谁就是那个用户,所以在web领域没有绝对的安全
-
浏览器也有资格拒绝保存服务端发送过来的cookie
七、django操作cookie
1.cookie与三板斧
操作cookie就不能直接返回HttpResponse对象,需要我们先拿到HttpResponse用变量接收
# render
obj1 = render()
return obj1
# HttpResponse
obj2 = HttpResponse()
return obj2
# redirect
obj3 = redirect()
return obj3
2.关于Cookie的方法
# 设置Cookie
def cookie_test(request):
# 浏览器向该地址发一个请求,就在浏览器写入 name = duoduo
obj = HttpResponse('ok')
obj.set_cookie('name', 'duoduo') # 写入到浏览器了,在http响应头里:cookie: name=Darker
obj.set_cookie('age', '18') # 写入到浏览器了,在http响应头里:cookie: name=Darker
return obj
# 取出Cookie
def get_cookie(request):
print(request.COOKIES)
print(request.COOKIES.get('name'))
return HttpResponse(f'我拿到了你的cookie,name是:{request.COOKIES.get("name")} ,age是:{request.COOKIES.get("age")}')
- path 只获取用户输入的路由信息
- path_info 只获取用户输入的路由信息
- get_full_path() 获取用户输入的路由信息+ 问号后面携带的数据
3.基于cookie编写用户登录注册功能
(1)初级版本
def login_func(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'duoduo' and password == '123':
obj = redirect('/home/')
obj.set_cookie('name', username)
return obj
return render(request, 'loginPage.html')
- 校验登录的装饰器
def login_auth(func_name):
def inner(request, *args, **kwargs):
# 拿到cookie
if request.COOKIES.get('name'):
res = func_name(request, *args, **kwargs)
return res
return redirect('/login/')
return inner
(2)进阶版本
用户没有登录之前想访问某个网站,在输入用户名密码之后,就应该跳转回之前的网站
def login_func(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'jason' and password == '123':
target_path = request.GET.get('next')
if target_path:
obj = redirect(target_path)
else:
obj = redirect('/home/')
obj.set_cookie('name', username)
return obj
return render(request, 'loginPage.html')
- 校验用户登录的装饰器
def login_auth(func_name):
def inner(request, *args, **kwargs):
# request.path_info 只获取用户输入的路由信息
target_path = request.path_info
# 拿到cookie
if request.COOKIES.get('name'):
res = func_name(request, *args, **kwargs)
return res
return redirect('/login/?next=%s' % target_path)
return inner
八、django操作session
由于session是保存在服务端的用户相关的数据,就因该有个地方存储session,保存数据都在数据库中,所以当我们执行迁移命令的时候,Django就会自动帮我们创建django_session的表,用来存储session
- 如图,执行迁移命令后,django自动创建的session表
django默认的的session失效时间是14天
1.设置session
request.session['key'] = value
(1)生成一个随机字符串
(2)对value数据做加密处理,在django_session表中存储
- 随机字符串 :也就是加密的数据
(3)将随机字符串也发送一份给客户端cookied保存
- sessionid :随机字符串
2.获取session
request.session.get('key')
(1)自动获取随机字符串
(2)去Django_session表中根据随机字符串获取加密的数据
(3)自动解密数据并处理到request.session.get()中
3.补充
1.session可以设置过期时间
2.存储session数据的位置也可以修改