Django框架——cookie与session简介、django操作cookie与session、django中间件

发布时间 2023-05-06 21:00:55作者: 抱紧小洪

cookie与session简介

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

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

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

'''编写一个真正的用户登录功能'''
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
        else:
            return redirect('/login/')
    return inner

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


'''进阶操作:用户没有登录之前想访问某个网站输入用户名密码之后就应该调回改网站'''
def login_func(request):
    if request.method == 'POST':
        username == resquest.POST.get('username')
        password == resquest.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):
        target_path = request.path_info  # 只获取用户输入的路由信息
        if request.COOKIES.get('name'):
        	res = func_name(request,*args,**kwargs)
        	return res
        else:
            return redirect('/login/?next=%s' % target_path)
    return inner

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.session.get()中
        
补充说明
	1.可以设置过期时间  # request.session.set_expiry(5)  # 默认是秒为单位
    2.存储session数据的位置也可以修改

'''代码演示'''
def set_se_func(request):
    # 会自动转换成字符串的形式存储在表中
    request.session['desc'] = '时间过的真快 又要干饭了 还是疯狂星期四!!'
    # 设置过期时间
    request.session.set_expiry(5)  # 默认是秒为单位
    return HttpResponse('稍微屯点吃的')

def get_se_func(request):
    # 存储在表中的数据会自动解密到session.get中
    print(request.session.get('desc'))
    return HttpResponse('再坚持一会会')

django中间件

django默认有七个中间件 并且还支持用户自定义中间件
中间件主要可以用于:网站访问频率的校验 用户权限的校验等全局类型的功能需求
  
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. 在项目名下或者应用名下新建一个任意名称的文件夹
2. 在这个文件夹下面新建一个py文件
3. 在这个py文件中,新建一个类,必须继承MiddlewareMixin
4. 在你新建的这个类下面可以写哪几个方法:
	process_reqeust  # 需要传request参数
    process_response  # 需要传request和response参数
    process_view
    process_exception
    process_template_response
5. 一定要在配置文件的中间件里面注册你的中间件路径

from django.utils.deprecation import MiddlewareMixin

class MyMiddleware001(MiddlewareMixin):
    def process_request(self,request):
        print('from MyMiddleware001 process_request')

    def process_response(self,request,response):
        print('from MyMiddleware001 process_response')
        return response
    
在类中编写五个可以自定义的方法
	需要掌握的
    	process_request
        	1.请求来的时候会从上往下一次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
            2.如果该方法自己返回了HttpResponse对象那么不再往后执行而是直接原路返回
        process_response
        	1.响应走的时候会从下往上依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
            2.该方法有两个形参request和response  形参response指代的就是后端想要返回给前端浏览器的数据 该方法必须返回该形参 也可以替换
        '''如果在执行process_request方法的时候直接返回了HttpResponse对象那么会原路返回执行process_response 不是执行所有的'''

django中间件三个了解的方法

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

基于django中间件的功能设计

将各个功能制作成配置文件的字符串形式
	如果想拥有该功能就编写对应的字符串
    如果不想有该功能则注释掉对应的字符串
   
补充知识
	如果利用字符串导入模块
import importlib
s1 = 'bbb.b'
res = importlib.import_module(s1)  # from bbb import b
print(res)  # <module 'bbb.b' from 'D:\\pythonProject03\\djangomiddle\\bbb\\b.py'>
'''注意字符串的结尾最小单位只能是py文件 不能是py文件里面的变量名'''

需求分析
	模拟编写一个消息通知功能(微信、qq、邮箱)
    
方式1:基于函数封装的版本
	没有眼前一亮的感觉 很一般
方式2:基于django中间件的功能设计(插拔式设计)
#########################################
项目名
	notify
    	__init__.py
        	from settings import NOTIFY_LIST
            import importlib

            def send_all(content):
                for full_path in NOTIFY_LIST:
                    module_path,class_str_name = full_path.rsplit('.',maxsplit=1)
                    # 1.利用字符串导入模块 拿到模块名
                    module_name = importlib.import_module(module_path)
                    # 2.利用反射从模块中获取字符串对应的类名
                    class_name = getattr(module_name,class_str_name)
                    # 3.利用类名加括号产生对象
                    obj = class_name()
                    # 4.对象调用发送消息的方法
                    obj.send_msg(content)
        email.py
        	class Email(object):
    			def __init__(self):
        			pass

    			def send_msg(self,content):
        			print('来自email的消息>>>%s' % content)
        qq.py
        	class Qq(object):
    			def __init__(self):
        			pass

   				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)
    settings.py
    	NOTIFY_LIST = [
    	'notify.email.Email',
    	'notify.qq.Qq',
   		'notify.weixin.Weixin',
		]
    start.py
    	import notify

		if __name__ == '__main__':
    	notify.send_all('你酱紫认真!!')
#########################################