Day77--阶段复习02--类的魔法方法及cookie与session
2021/11/17 6:39:42
本文主要是介绍Day77--阶段复习02--类的魔法方法及cookie与session,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
今日内容
1. 后续课程安排
1 drf框架 2 git 3 redis使用 4 路飞项目(celery异步) 5 爬虫(mongodb) 6 linux 7 cmdb项目(资产收集) 8 代码发布系统 9 flask框架(给你一到两个项目) 10 数据结构和算法 11 docker,dockercompose(用docker部署项目,nginx负载均衡,横向扩展),k8s(看情况) 12 就业辅导(redis高级,Elasticsearch,如何提高项目并发量,分布式锁,分布式id,远程连接docker开发,git冲突如何解决)
2. 作业讲解
# 作业:用中间件或者装饰器前端不管传json还是其他格式,request对象中有个data属性 # 思路:用json.load()方法 直接将json格式转成Python类型;若成功,则说明请求数据是json格式;反之失败,则是普通post的请求数据 # 核心代码(中间件) from django.utils.deprecation import MiddlewareMixin import json class JsonMiddel(MiddlewareMixin): def process_request(self, request): try: request.data=json.loads(request.body) except Exception as e: request.data=request.POST # 关注的问题(注意): 1.form表单和ajax提交的重复: form表单中的提交使用 input的submit类型 或者 button id='submit',但却用了Ajax的button按钮来提交,此时会触发两次提交数据,从而出现重复或者错误。 解决办法:将form表单的 input的submit类型,改成 input的button类型 (就是普通的按钮,不会触发form表单提交),只采用Ajax来提交数据 2.from django.http.request import QueryDict 读这个源码 QueryDict对象 本质就是一个字典,比字典强大;但不能修改其中的值,一改就报错 (就是利用__setattr__() :在字典.属性=值时,自动触发该方法,进行拦截处理) 3.CommonMiddleware中间件 控制了url请求路径是否重定向到 '原路径+/' 的地址 # 取消自动加斜杠 (setting.py) APPEND_SLASH = False/True # 默认是自动加斜杠的 # django.middleware.common.CommonMiddleware 读这个中间件源码
3. python中的魔法方法
# __init__:类实例化会触发 # __str__:打印对象会触发 # __call__:对象()触发,类也是对象 类(),类的实例化过程调用元类的__call__ # __new__:在类实例化会触发,它比__init__早(造出裸体的人,__init__穿衣服) # __del__:del 对象,对象回收的时候触发 # __setattr__,__getattr__: ( .拦截--点拦截方法 ) 当对象.属性是赋值会调用setattr,如果是取值 会调用getattr # __getitem__,__setitem__: ( []拦截--中括号拦截方法) 当对象[属性]是赋值会调用setitem,如果是取值 会调用getitem # __enter__和__exit__ 上下文管理器
3.1 setattr,getattr,setitem,getitem演示
# 案例一:普通类(继承object) 允许'.'方法,但不支持'[]' class Person: def __init__(self,name): self.name=name def __setitem__(self, key, value): setattr(self,key,value) # 反射赋值:用Python内置方法 setattr() def __getitem__(self, item): return getattr(self,item) # 反射取值: 用Python内置方法 getattr() p=Person('lqz') p.name='ppp' # 对象自带 __setattr__()方法 不报错 print(p.name) # 'ppp' p['name']=10 # 报错,如何可行:重写__setitem__()方法 print(p['name']) # 10 # 案例二:字典类 允许'[]'方法,但不支持'.' dic={'name':'lqz','age':19} print(dic['name']) # 'lqz' print(dic.name) # 报错 class Mydic(dict): def __setattr__(self, key, value): print("对象加点赋值,会触发我") self[key]=value def __getattr__(self, item): print("对象加点取值,会触发我") return self[item] # 不要加引号 mydic=Mydic(name='lqz',age=18) print(mydic['name']) # 'lqz' print(mydic.name) # 'lqz' mydic.name=99 print(mydic.name) # 99 # 自我总结规律: 有些数据类型 要嘛能使用'.'方法赋值或取值,要嘛能使用'[]'方法赋值或取值 要想实现另一种,则重写其类中的魔法方法,再通过内部的点或中括号来实现
3.2 with 上下文管理器
# __enter__() 与 __exit__()组合使用,可将 对象类似于文件 作为上下文管理器来打开使用 # 应用场景:常用于数据库链接操作 进入时:打开数据库链接,并返回链接对象conn给as; 退出时:关闭数据链接; 缩进内:执行正常的数据库操作 class Person: def __enter__(self): print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量') return 'oo' def __exit__(self, exc_type, exc_val, exc_tb): print('退出with代码块时执行此方法') print('1', exc_type) print('2', exc_val) print('3', exc_tb) with Person() as p: # 这句话执行,会触发类的__enter__ print(p)
3.3 对象比较 '==' :eq
# __eq__(self,obj) :自定义比较判断两个对象 class A: def __init__(self,x,y): self.x = x self.y = y def __eq__(self,obj): # 打印出比较的第二个对象的x值 print(obj.x) if self.x +self.y == obj.x+obj.y: return True else: return False a=A(1,2) b=A(99,3) print(a==b) # 当执行'=='时,会触发__eq__的执行,并且把b传进去,就是obj # 发现:'=='后只要是对象,就可以传进去,就是object
4. cookie,session,token
# HTTP协议:无状态,无连接,基于请求响应,基于tcp/ip的应用层协议 # 具体详细分:请求协议(请求头 请求体),响应协议(响应头 响应体) # 复习 # mysql:c/s架构:底层基于socket,自己封装的协议,mysql的客户端:navicate(c++图形化界面,实现了请求和响应协议),pymysql(用python语言实现了请求和响应协议) # redis:c/s架构:底层基于socket,自己封装的协议 # docker:c/s架构,基于http协议,使用restfull规范 # elasticsearch:c/s架构,基于http协议,使用restfull规范 # cookie:是存在于浏览器的键值对,向服务端发送请求,携带它过去(缺陷:不安全) # session:存在于服务端的键值对(放在哪?内存中、文件、mysql、redis) # 缺陷:如果用户量很大,存储需要耗费服务器资源 # token:就是个字符串(通过加密算法和密钥加密的字符串 既安全,又存个人信息) 现在应用非常广泛,契合了前后端分离(只存储在前端上,服务器只做校验), 就不管前段是浏览器,是移动APP,还是微信小程序,只要请求给后端一个token字符串 就都可以访问 (token在浏览器上保存时就是cookie) # JWT:json web token (json格式的token) 主流
5. django中的session底层原理
# 请求来的时候: # 1.通过请求cookie request中的sessionId,取出随机字符串 # 2.根据随机字符串,去数据库中session表 查出对应的值 # 3.将数据转成字典( {随机字符串:对应session值} ),赋值给request.session, 后面视图函数中就可以操作它了 # 响应走的时候 # 1.在中间件的process_response中,取出request.session的modify属性值 # 2.判断modify值是否是true # 2.1如果是true,表示在视图函数中改过session,数据库中session表同步修改 # 2.2如果是false,就不修改,直接返回给前端(sessionId:随机字符串)
6. 异常处理
# 最基本的异常 class NotStrException(BaseException): def __init__(self,msg): self.msg=msg def __str__(self): return self.msg try: except: else: # 什么时候执行 finally: try: print("xxx") # print(1/0) except Exception as e: print(e) else: # 基本上不会用到 print("正常执行且没有出异常时,会走") finally: print("我是finally") # 永远会走,无论是否有异常
7. pymysql的使用
import pymysql #连接数据库 conn=pymysql.connect(host='101.133.225.166', user='root', password="123456",database='test', port=3306) # 获取游标 cursor=conn.cursor() # 默认查出来数据是元祖格式,参数cursor=pymysql.cursors.DictCursor 数据是字典格式 # 操作 定义一个sql 查询 sql='select id,name from book' cursor.execute(sql) ret=cursor.fetchall() print(ret) # 插入 %s 是防止sql注入的问题 sql='insert into book(id,name) values (%s,%s)' cursor.execute(sql,[3,'lqz']) conn.commit() # 删除 sql='delete from book where name=%s' cursor.execute(sql,['lqz']) conn.commit() # 更新 sql='update book set name=%s where id=%s' cursor.execute(sql,['xxx',1]) conn.commit()
作业
# 1 写一个类,有个name属性,如果name赋值为非字符串,就不让放 # isinstance(value, str)判断是否是实例对象 issubclass() 判断是否是子类 class Person: def __init__(self, name): self.name = name def __setattr__(self, key, value): if isinstance(value, str): # self.key = value # 与 setattr(self, key, value) 类似,都会递归调用触发 self.__setattr__() 就无限递归下去了 # 解决一: 用内部字典的形式修改值 self.__dict__[key] = value # 解决二:重用父类的__setattr__() super().__setattr__(key, value) # 或指名道姓: object.__setattr__(self, key, value) else: print('name 值必须为字符串') p = Person('jason') print(p.name) # 'jason' p.name = 99 print(p.name) # 'name 值必须为字符串' # 2 通过上下文管理器写一个mysql的连接,通过with管理 import pymysql class mysql: def __enter__(self): self.conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123456', database='bbs', charset='utf8', ) self.cursor = self.conn.cursor() return self.cursor def __exit__(self, exc_type, exc_val, exc_tb): self.conn.close() with mysql() as cursor: sql = 'select title from app01_article' cursor.execute(sql) res = cursor.fetchall() print(res) # 3 使用django实现token功能 浏览器保存token {'token': 'user_id|加密后的签名'} user_id=name+pwd # 自我实现 # 问题:处理请求和处理响应没办法同时进行 # 未生成token:执行process_response() 给浏览器生成一个本地用户token # 有token后:执行process_request() 验证浏览器上的token from django.utils.deprecation import MiddlewareMixin from django.http import HttpResponse import hashlib class TokenMiddleware(MiddlewareMixin): def process_request(self, request): # 1.从前端cookie取出token值 token_value = request.COOKIES.get('token') # 注意格式是字符串 # 2.以'|'分割token的 id和签名部分 user_id, sign = token_value.split('|') # 3.将id加密 encrypt = hashlib.md5(user_id.encode('utf-8')).hexdigest() # 4.判断是否与签名一致 if encrypt != sign: return HttpResponse('登录失败,token已被篡改') def process_response(self, request, response): name = request.POST.get('name') pwd = request.POST.get('pwd') user_id = name + pwd token_value = user_id + '|' + hashlib.md5(user_id.encode('utf-8')).hexdigest() response.set_cookie('token', token_value) return response
这篇关于Day77--阶段复习02--类的魔法方法及cookie与session的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-02在 Objective-C 中strong 和 retain有什么区别-icode9专业技术文章分享
- 2024-11-02NSString 中的 hasPrefix 有什么作用-icode9专业技术文章分享
- 2024-11-02在 C 和 Objective-C 中inline的用法是什么-icode9专业技术文章分享
- 2024-11-02文件掩码什么意思?-icode9专业技术文章分享
- 2024-11-02在 Git 提交之前运行 composer cs-fix 命令怎么实现-icode9专业技术文章分享
- 2024-11-02为 Composer 的 cs-fix 命令指定一个目录怎么实现-icode9专业技术文章分享
- 2024-11-02微信公众号开发中怎么获取用户的 unionid-icode9专业技术文章分享
- 2024-11-01lip-sync公司指南:一文读懂主要玩家和技术
- 2024-11-01Anthropic的新RAG方法——提升大型语言模型在特定领域的表现
- 2024-11-01UniApp 中组件的生命周期是多少-icode9专业技术文章分享