首页 > 其他分享 >django中间件需要了解的方法 importlib模块 django操作cookie django操作session

django中间件需要了解的方法 importlib模块 django操作cookie django操作session

时间:2022-12-24 22:45:36浏览次数:36  
标签:cookies 浏览器 中间件 request django session 字符串

目录

django中间件三个需要了解的方法

1.process_view
	路由匹配成功之后执行视图函数/类之前自动触发(顺序同process_request)
2.process_exception
	视图函数/类执行报错自动触发(顺序同process_response)
3.process_template_response
	视图函数/类返回的HttpResponse对象含有render并且对应一个方法的时候自动触发(顺序同process_response)

首先自定义中间件:
image-20221222091545593

定义完之后要对中间件进行注册

process_view

image-20221222092053234

process_view何时触发:
路由匹配成功之后,执行视图函数/类之前自动触发。(顺序同process_request,经过每一个中间件。)

执行顺序:

image-20221222091840440

process_exception

在类中添加此方法:
image-20221224144031367

process_exception何时触发:
如下图可见此方法在正常的一次请求流程中不会触发:image-20221222092344976

exception和异常相关。当执行视图函数的时候报错了,自动触发。
image-20221222092434485

注意是从下往上执行,process_exception的形参接受视图函数的报错信息。
image-20221222092514381

process_template_response

image-20221222092655626

注意:参数有response的都要使用return进行返回。

执行顺序:

image-20221222092717384

可发现在正常的一次请求流程中此方法没有执行。

process_template_responsed方法的执行条件:
视图函数、视图类返回的Httpresponse对象含有render属性,并且render属性对应一个render方法的时候自动触发。
image-20221222092824727

示例:
image-20221222092848171

基于django中间件实现功能的插拔式设计

将各个功能制作成配置文件的字符串形式
	如果想拥有该功能就编写对应的字符串
	如果不想有该功能则注释掉对应的字符串
 
补充知识	
	如果利用字符串导入模块
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'>
'''注意字符串的结尾最小单位只能是py文件 不能是py文件里面的变量名'''
思考django中间件是如何处理的(最小单位是类名)


需求分析
	模拟编写一个消息通知功能(微信、qq、邮箱)
 
方式1:基于函数封装的版本
	没有眼前一亮的感觉 很一般
方式2:基于django中间件的功能设计
 	眼前一亮 回味无穷

django中间件中每个字符串都代表特定的功能。
这就叫功能的插拔式设计。image-20221222094646821

也就是说写字符串相当于导入了某个模块:
image-20221222095023331

正常情况下导模块需要用到import句式:
image-20221222095146882

示例:

image-20221222095218008

importlib模块

importlib模块支持传递字符串来导入模块。
如下使用importlib模块与使用import句式会获得相同的结果。

使用importlib模块:image-20221222095316813

使用from ... import ...句式:
image-20221222095335747

更多例子:

import importlib
import b
str_module = 'b'
res = importlib.import_module(str_module)
print(type(res))  # <class 'module'>
print(type(b))  # <class 'module'>

importlib模块底层原理:
将字符串按照点切割:
image-20221222095449882

importlib中的字符串的结尾最小单位只能到py文件名,而不能是py文件的的某个变量名。

如下图desc是b.py文件中的变量名:image-20221222095735092

需求分析:
编写一个消息通知功能(微信、qq、邮箱都会收到消息)。

方式1:基于函数封装

每个功能都写一个函数:

image-20221222100124727

封装总方法:
image-20221222100239455

方式2:基于django中间件的功能设计

创建配置文件settings.py、启动文件start.py。再创建三个功能文件放入notify目录。

image-20221222100610144

实现功能拆分,进行解耦合。

email功能文件下,写一个功能类:
image-20221222100705034

核心功能函数send_msg:

image-20221222100741007

不同的类,当有相同的功能时,他们的名字也应该相同(多态性):

image-20221222101009380

只要发消息,就使用send_msg方法。

编写settings.py:
image-20221222101249968

思考django中间件是如何处理的:

notify是一个包,在start.py导入包名notify:
image-20221222101453305

导入包名notify实际是导入的包中的__init__文件。

start.py文件中,执行settings定义的函数send_all:

image-20221222101631957

__init__文件中导入settings.py文件内的列表:

image-20221222101753207

for循环取出列表中的字符串,并使用rsplit方法做切分:
image-20221222101848005

得到用字符串表示模块路径、模块中的类名:

image-20221222101904293

使用importlib模块的功能,通过字符串获得模块类型:

image-20221222102006200

由于模块也是对象,通过反射从模块中拿名字:(也就是拿到真正的类)
image-20221222102148963

类名加括号产生对象:
image-20221222102231397

这个对象里面就有send_msg方法了,调用send_msg传入参数,实现功能。

cookie与session简介

"""
回忆:HTTP协议四大特性
	1.基于请求响应	
	2.基于TCP、IP作用于应用层之上的协议
	3.无状态
		不保存客户端的状态
	4.无连接
"""
最开始的网站都不需要用户注册 所有人来访问获取到的数据都是一样的
随着互联网的发展很多网站需要指定当前用户的状态

cookie
	保存在客户端与用户状态相关的信息
session
	保存在服务端与用户状态相关的信息
ps:session的工作需要依赖于cookie
    
补充:浏览器有资格拒绝保存服务端发送过来的cookie数据

早期cookies

最开始的浏览器,每次向服务器的请求都自报家门,即每发一次请求,都把用户名和密码都发过去:
image-20221224160459720

当用户第一次把用户名和密码输对了之后。浏览器自动保存用户名和密码。发请求时,浏览器自动帮你输入用户名密码。

浏览器有能力记住不同网站的用户名和密码。此时浏览器也就是客户端。

产生了cookie的定义:
保存在客户端与用户状态相关的信息(通常情况下类似于字典的kv键值对)

早期的cookies很不安全:
真实的用户名密码保存在浏览器不安全。万一有人打开你的电脑,窃取你浏览器的密码。

随机字符串解决cookies安全问题

所以采取了以下办法:
当第一次输对了用户名和密码,服务端会给你发一个随机字符串。服务端有一张表记着字符串和用户的对应关系。下次访问服务端的时候,你把这个随机字符串带上,服务端可以通过表来确定这个随机字符串对应哪个用户。

这样做的好处:
外人查看随机字符串,也无法查看用户的密码。而用户可以拿着随机字符串进行登录。

session的定义:
用户真正的数据保存在服务端,所以我们把保存在服务端中,跟用户状态相关的信息叫做session。

随机字符串叫什么?
随机字符串既存在于浏览器,也存在于服务端。
在客户端上叫cookies 。
在服务端上叫session。

注意:
session是不可能单独工作的,要依赖于cookies。
所有跟用户状态相关的操作 都要依赖于cookies

禁止浏览器保存cookies

在开发者工具的application查看cookies:image-20221222105756633

浏览器有资格拒绝保存cookies:
image-20221222110103357

禁用cookies后无法进行登录:

image-20221222110129763

django操作cookie

from django.shortcuts import render,HttpResponse,redirect
return render()
return HttpResponse()
return redirect()

要想操作cookie就不能直接返回HttpResponse对象 必须先用变量接收
obj1 = render()
return obj1
obj2 = HttpResponse()
return obj2
obj3 = redirect()
return obj3

要想操作cookie就不能直接返回HttpResponse对象 必须先用变量接收。
如下图,先产生HttpResponse对象,再用对象调用set_cookie方法,此方法让浏览器保存键值对:

image-20221222110953999

查看浏览器报错的cookies键值对:

image-20221222111031284

request.COOKIES

通过request.COOKIES查看cookies键值对:
image-20221222111125277

因为浏览器现在已经有cookies,所以每次访问路由都会携带cookies。

用户登录功能

def login_func(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason' and password == '123':
            obj = redirect('/home/')
            obj.set_cookie('name', username)
            return obj
    return render(request, 'loginPage.html')

前端编写表单:

image-20221222111348850

后端视图函数:

image-20221222111435905

让客户端保存凭证,并重定向回home页面
(Home页面只有登录的用户才可以查看):
image-20221222112751092

Homepage获取cookies:
image-20221222112843597

服务器询问你的cookies有没有name这个键。当浏览器携带cookies时,才能访问home页面,没有cookies就重定向回登录页面。

给视图函数添加装饰器

def login_auth(func_name):
    def inner(request, *args, **kwargs):
        if request.COOKIES.get('name'):
            res = func_name(request, *args, **kwargs)
            return res
        return redirect('/login/')

    return inner


@login_auth
def home_func(request):
    return HttpResponse('home页面 只有登录的用户才可以查看')

新需求:
需要登录才能访问的页面有好几个.
image-20221222113239668

极端情况:
我们有三百个视图函数,视图函数返回的页面,登录之后的用户才能查看。

在不影响函数原有的功能的基础下,给其添加新功能,可以使用:
装饰器

image-20221222113639498

在请求访问该页面的时候携带cookies时,继续执行视图函数。
请求未携带cookies时,重定向回登录页面。

给多个视图函数添加装饰器:
image-20221222113709563

登录成功后重定向回原页面

进阶操作:
用户没有登录之前访问某个页面,此时让用户跳转到登录页面,用户输入用户名密码登录之后,跳回用户原来想访问的页面。

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):
        # print(request.path)  # 只获取用户输入的路由信息
        # print(request.path_info)  # 只获取用户输入的路由信息
        target_path = request.path_info
        # print(request.get_full_path())  # 获取用户输入的路由信息+问号后面携带的数据
        if request.COOKIES.get('name'):
            res = func_name(request, *args, **kwargs)
            return res
        return redirect('/login/?next=%s' % target_path)

    return inner

获取路由的三个方法

image-20221222114130997

查看三个方法返回的结果:
image-20221222114159121

三个方法的区别:访问home路由时,使用问号携带一些信息。
image-20221222114225109

第三个方法,可以获取整个路由,并且也可以获取问号携带的信息:
image-20221222114246330

总结:

image-20221222114320368

为了实现上述需求,我们使用path_info方法:
先获取用户想访问页面的路由信息,存储在变量名target_path中:
image-20221222114454101

跳转到登录页面时,通过问号携带信息:
如下例子中,用户登录之前想访问的页面路由是/home1/

image-20221222114540284

之前登录成功之后,我们重定向的页面时写死的:

image-20221222114659570

现在我们添加判断:

target_path不存在的情况,意味着用户是直接访问的登录页面。
此时的request.GET.get('next')是获取不到值的,因为这个获取的是路由后面通过问号携带的信息。此时走else分支:跳转回home首页

当target_path存在的情况,意味着用户是从别的页面跳转过来的。此时通过request.GET.get('next')获取用户是从哪里来的。然后给他重定向回到原页面。

image-20221222114735184

django操作session

由于session是保存在服务端上面的数据 就应该有个地方能够存储
我们只需要执行数据库迁移命令即可 django会自动创建很多需要的表


django默认的session失效时间是14天


设置session	
	request.session['key'] = value
        1.生成一个随机字符串
        2.对value数据做加密处理 并在django_session表中存储
            随机字符串>>>加密数据
        3.将随机字符串也发送一份给客户端保存(cookie)
            sessionid:随机字符串
获取session	
	request.session.get('key')
        1.自动获取随机字符串
        2.去django_session表中根据随机字符串获取加密的数据
        3.自动解密数据并处理到request.sesion.get()中
    
补充说明
	1.可以设置过期时间		
 	2.存储session数据的位置也可以修改 各种数据库 甚至一个文件

session保存的位置

由于session是保存在服务端上面的数据 就应该有个地方能够存储
我们只需要执行数据库迁移命令即可 django会自动创建很多需要的表

django默认的session失效时间是14天

如下图所示,django自动创建的表中,有一张session表:

15515

自动创建的session表有如下字段:

image-20221224204928400

设置session

设置session	
	request.session['key'] = value
        1.生成一个随机字符串
        2.对value数据做加密处理 并在django_session表中存储
            随机字符串>>>加密数据
        3.将随机字符串也发送一份给客户端保存(cookie)
            sessionid:随机字符串

示例:

image-20221224204623583

在没有进行数据库迁移的情况下,执行这条命令会报错:

image-20221224204838215

正常执行这条命令,会将session表里添加一条数据:

image-20221224205050477

session_data:
存储真正跟用户相关的数据,
我们设置session时使用的是:request.session['key'] = value
而session_data存储的是一个加密过的字典,这个加密字典的键和值就是上面设置session时的键和值。
举个例子:request.session['username']= 'cloud'
那么session中存储的就是加密过的{'username':'cloud'}

session_key:
存储的是加密算法产生的随机字符串。

expire_date:
存储session的过期时间。django中默认的session失效时间是14天。

流程推导(重要)

  1. 浏览器朝服务端发请求。
  2. 服务端创建session。
    服务端在django_session表中,
    生成随机字符串(session_key)、加密之后的用户数据(session_data)
  3. 服务端将随机字符串(session_key)发送给浏览器保存,此时这个随机字符串就称之为cookies.

查看浏览器保存的session_key:

image-20221224210832427

浏览器是以键值对的形式保存的,键是浏览器自己取的,不必在意。这个值就是服务端发送过来的session_key。

下次浏览器访问服务端,就会自动携带session_key(cookies),服务端会拿着浏览器带来的session_key去保存session的表中进行校验,查看是否有相同的字符串。

image-20221224214850551

获取session

获取session	
	request.session.get('key')
        1.自动获取随机字符串
        2.去django_session表中根据随机字符串获取加密的数据
        3.自动解密数据并处理到request.sesion.get()中

示例:
image-20221224211636750

流程推导(重要)

image-20221224205050477

  1. 服务端接受浏览器传过来的加密字符串(session_key)
  2. 拿着加密字符串去session表中查找
  3. 当查找到相同的字符串,取出其对应的session_data
  4. 对session_data自动解密,并处理到request.sesion.get()中

设置session过期时间 set_expiry

示例:
image-20221224212436084

set_expiry:设置session的过期时间,括号里填写的单位是秒,这里的意思是session创建后3秒就过期。

标签:cookies,浏览器,中间件,request,django,session,字符串
From: https://www.cnblogs.com/passion2021/p/17003489.html

相关文章

  • django中只使用ModleForm的表单验证,而不使用ModleForm来渲染
    主题众所周知,django.forms极其强大,不少的框架也借鉴了这个模式,如Scrapy。在表单验证时,django.forms是一绝,也是面向对象的经典表现。但要用它来渲染表单那就不好玩了,除非写......
  • django中间件
    django中间件相当于django框架的保安,只要数据过来必须经过中间件的校验。django中间件默认有7个。可以在setings内MIDDLEWARE里查看看着是字符串其实底层就是导模块的......
  • cookie与session
    cookie与session简介早期的web不需要什么用户注册,所有用户都给一样的界面,不需要什么状态保存,随着互联网的发展,我们很多web框架的应用需要保存用户的状态。cookie保存在......
  • spring mvc——SpringMVC常用注解——SessionAttributes注解——(将数据存储到session
                                                        ......
  • django中间件了解的三个方法、基于Django的插拔式设计、cookie与session简介、基于Dja
    目录Django中间件三个了解的方法1.process_view2.process_exception3.process_template_response基于Django中间实现功能的插拔式设计模拟编写一个消息通知功能(微信、qq、......
  • 1005.Django自定义过滤器及标签
    一、关于自定义自定义的引入内置函数--------->自定义函数内置模块--------->自定义模板内置过滤器------>自定义过滤器内置标签--------->自定义标签二、文件路径配......
  • Django
    第1章1.自己开发web框架web种类:第一种,帮你把下面所有的事都做了。Tornado:做了所有的事。第二种,不办你做socket的事,再的都帮你做了。wsgiref:做socket服务......
  • 1004.Django模板标签
    一、常用标签模板标签标签在渲染的过程中提供任意的逻辑。这个定义是刻意模糊的。例如,一个标签可以输出内容,作为控制结构,例如“if”语句或“for”循环从数据库中提取内......
  • 框架第十一课---django中间件三个了解的方法,基于django中间件实现功能的插拔式设计,coo
    昨日内容回顾forms组件渲染标签form_obj=MyForm()方式1:form_obj.as_p\form_obj.as_ul\form_obj.as_table方式2:form_obj.username.labelform_obj.username方......
  • django_ORM基础字段和选项
     一、修改ORM1、任何关于表结构的修改,务必在对应模型类上修改。2、在上一篇博文中,创建了bookstore_book表,如果需要再添加一个名为info(varchar100)的字段,则需要如下操......