Django框架:12、Django中间件(了解)、功能插拔式设计、cookie和session

Django框架

一、Django中间件

简介

  • 客户端信息在经过web协议后进入django框架,中间件类似与保安,会对这些信息进行处理、判断

  • 中间件主要可以用于:网站访问频率的校验 用户权限的校验等全局类型的功能需求

  • Django默认一共有七个中间件,同时还支持自定义中间件

查看中间件

  • 可以在settings.py文件中的MIDDLEWARE中查看中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

1、自定义中间件

# 1、在项目文件中创建存储中间件的py文件:
	My_middleware
      |---My_middleware.py
        
# 2、参考Django自带中间件代码的编写方式进行编写:
    from django.utils.deprecation import MiddlewareMixin


    class My_midd01(MiddlewareMixin):
        pass

# 3、观察Django自带中间件,发现每个中间件中都含有两个固定功能:
	def process_request(self, request):pass
	def process_response(self, request, response):pass


# 4、在自己编写的中间中添加这两个功能函数
	import re
    from django.conf import settings
    from django.http import HttpResponsePermanentRedirect
    from django.utils.deprecation import MiddlewareMixin


    class My_midd01(MiddlewareMixin):
        def process_request(self, request):
            print('request01')
    
    
    	  def process_response(self, request, response):
            print('response01')

 # 5、模拟客户端发送消息,发现:
	process_request:
    	1.请求来的时候会从上往下依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
      2.如果该方法自己返回了HttpResponse对象那么不再往后执行而是直接原路返回
    
	process_response:
    	1.响应走的时候会从下往上依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
       2.该方法有两个先request和response 形参response指代的就是后端想要返回给前端浏览器的数据 该方法必须返回该形参 也可以替换
             '''如果在执行process_request方法的时候直接返回了HttpResponse对象那么会原路返回执行process_response 不是执行所有'''
        
        
# 6、一定在配置文件中注册中间件才可以生效

2、需要了解的三个方法

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

二、功能的插拔式设计

​ 在使用Django时,我们发现Django中间件都是以字符串的形式所配置的,通过了解发现这些以字符串配置的中间件其实就是导入了对应的模块,这种巧妙的设计实现了插拔式的功能,当我们需要使用时只需要输入对应的字符串,不要使用只需要注释即可

如何利用字符串导入模块

  • 模块:importlib
  • 注意事项:字符串的结尾最小单位只能是py文件 不能是py文件里面的变量名
# 1、导入模块:
import importlib

# 2、编写模块路径(字符串)
path_str = 'aaa.bbb.ccc'

# 3、将字符串形式的路径传给importlib产生的方法
res = importlib,import_module(path_str)  # form aaa.bbb impotr ccc

# 4、直接使用接收模块的变量名点出模块下的方法
res.func()

将字符串改为配置属性

功能视图层:
	# 1、将视图下py文件内的函数修改为类,并统一类下相同功能的函数名字
    emali.py
        class Email(object):
            def __init__(self):
                pass

            def msg(self, info):
                print(f'邮箱消息>>>:{info}')
    qq.py
    	class Qq(object):
            def __init__(self):
                pass

            def msg(self, info):
                print('QQ消息>>>:%s' % info)
    
    wechat.pyclass
    	Wechat(object):
            def __init__(self):
                pass

            def msg(self, info):
                print('微信消息>>>:%s' % info)
     
                

配置文件层
    settings.py
    	# 2、将所有类的路径以字符串的形式编写在列表中(以类名结尾)
       SET = ['view.email_view.Email',
               'view.qq_view.Qq',
               'view.wechat_view.Wechat',
              ]

视图层创建__init__.文件
    # 1、导入setting文件中的配置
    from setting import SET
    # 2、导入字符串转模块的模块文件
    import importlib

    # 3、创建函数,用来供启动文件使用
    def func_all(info):
        # 4、循环出配置文件下提前配置的路径
        for path in SET:
            # 5、将str路径进行切割,切割出最后的类名,交叉赋值
            dir_name, class_str_name = path.rsplit('.', maxsplit=1)
            # 6、将切割的前一部分转为模块
            res = importlib.import_module(dir_name)
            # 7、使用getattr功能判断类下是否有对象类的方法,并拿到实际类的对象
            class_name = getattr(res, class_str_name)
            # 8、将拿到的类产生出类的对象
            view_obj = class_name()
            # 9、使用类产生的对象直接点类下对应的方法
            view_obj.msg(info)
            
启动文件:
	# 1、导入视图文件
	import view
	# 2、直接使用__init__中的方法来启动所有配置中的str格式的模块方法
	view.func_all('周末怎么过?')

三、cookie与session

简介:

1、回想HTTP协议的四大特性:
	1.基于请求响应	
	2.基于TCP、IP作用于应用层之上的协议
	3.无状态
		不保存客户端的状态
	4.无连接

最开始的网站都不需要用户注册 所有人来访问获取到的数据都是一样的
随着互联网的发展很多网站需要指定当前用户的状态

例如:在我们登录某个网站后,再次访问该网站的其他网页就不需要在登陆,其实这都是cookie帮助我们保存了登录状态,在我们访问该网站的其他网页时,cookie会第一时间将我们的信息传递给服务端,这样服务端才可以识别出是‘我’在登陆

  • cookie:
    • 保存在客户端与用户端相关的信息
  • session:
    • 保存在服务端与用户状态的相关信息
    • session的工作依赖于cookie

1、django操作cookie

​ 想要操作cookie视图函数/类就不能直接返回HttpResponse对象,必须要使用变量进行接受,对变量进行操作,然后将变量进行返回出去

操作cookie

from django.shortcuts import render,HttpResponse,redirect

obj1 = render()
return obj1
obj2 = HttpResponse()
return obj2
obj3 = redirect()
return obj3

实际应用

编写一个真正的用户登录功能
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')

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页面 只有登录的用户才可以查看')



进阶操作:用户没有登录之前想访问某个网站输入用户名密码之后就应该调回该网站
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

2、django操作session

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

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

设置session
    request.session['key'] = value

当我们在设置session的时候会执行下列操作:

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

在获取session的时候会执行下列操作

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

总结

通过上面的知识点讲解我们可以发现session的使用非常简单,但是在底层来看,其实代码执行了非常多的操作,今后我们写代码也应该朝这方面靠拢.

def set_session(request):
    request.session['name'] = 'Like'  		# 设置Session
    return HttpResponse('设置Session')
'''
		    第一次运行的时候访问接口会发生报错    no such table: django_session
		    因为当客户端登录成功之后 服务端会产生一个随机字符串 返回客户端去保存(之所以要保存就是因为我们只有保存了这个字符串对应的信息,才能去进行信息校对,否则前端发送cookie我们无法识别)
		    服务端会针对这些字符串跟对应用户信息做一个保存 这个关系就保存在服务端执行迁移命令里面的Django_session表里面(但是目前我们第一次跑程序还没执行迁移命令)
		    表里面有三个字段 Session_key  Session_data Expire_date
		    session_ky    随机产生的一个加密字符串令牌
		    session_data  session数据
		    expire——date  django默认的session失效时间14天(不登录)

		    这个时候迁移命令创建完之后就可以访问接口了
	    '''

获取session中的注意事项


def get_session(request):                 # 获取session
    print(request.session.get('name'))
    return HttpResponse('获取Session')    # 自动会加密解密

'''
request.session['name'] = 'Like'
    1.django自动产生一个随机字符串返回给客户端(对name加密)
    2.往django_session创建数据(对jason加密)
request.session.get('name')
    1.自动从请求中回去sessionid对应的随机字符串
    2.拿着随机字符串去django_session中匹配数据
    3.如果匹配上还会自动解密数据并展示
 '''

posted @ 2023-01-02 16:58  kangshong  阅读(57)  评论(0编辑  收藏  举报