69-django-forms组件源码刨析、cookie与session
今日内容概要
-
forms组件源码
-
cookie与session
今日内容详细
forms组件源码
1 """ 2 切入点: 3 form_obj.is_valid() 4 """ 5 def is_valid(self): 6 """ 7 Returns True if the form has no errors. Otherwise, False. If errors are 8 being ignored, returns False. 9 """ 10 return self.is_bound and not self.errors 11 # 如果is_valid要返回True的话 那么self.is_bound要为True self.errors要为Flase 12 13 14 self.is_bound = data is not None or files is not None # 只要你传值了肯定为True 15 16 17 @property 18 def errors(self): 19 "Returns an ErrorDict for the data provided for the form" 20 if self._errors is None: 21 self.full_clean() 22 return self._errors 23 24 # forms组件所有的功能基本都出自于该方法 25 def full_clean(self): 26 self._clean_fields() # 校验字段 + 局部钩子 27 self._clean_form() # 全局钩子 28 self._post_clean() 29 30 31 # 通过看源码得到得第二种添加钩子提示的方式 32 from django.core.exceptions import NON_FIELD_ERRORS, ValidationError 33 34 def clean_username(self): 35 username = self.cleaned_data.get('username') 36 if '666' in username: 37 # self.add_error('username', '6个粑粑憨逼') 38 raise ValidationError('6个粑粑憨逼') 39 return username 40
cookie与session
""" 发展史 1.网站都没有保存用户功能的需求 所有用户访问返回的结果都是一样的 eg:新闻、博客、文章... 2.出现了一些需要保存用户信息的网站 eg:淘宝、支付宝、京东... 以登陆功能为例:如果不保存用户登陆状态 也就意味着用户每次访问网站都需要重复的输入用户名和密码(你觉得这样的网站你还想用吗?) 当用户第一次登陆成功之后 将用户的用户名密码返回给用户浏览器 让用户浏览器保存在本地,之后访问网站的时候浏览器自动将保存在浏览器上的用户名和密码发送给服务端,服务端获取之后自动验证 早起这种方式具有非常大的安全隐患 优化: 当用户登陆成功之后,服务端产生一个随机字符串(在服务端保存数据,用kv键值对的形式),交由客户端浏览器保存 随机字符串1:用户1相关信息 随机字符串2:用户2相关信息 随机字符串3:用户3相关信息 之后访问服务端的时候,都带着该随机字符串,服务端去数据库中比对是否有对应的随机字符串从而获取到对应的用户信息 但是如果你拿到了截获到了该随机字符串,那么你就可以冒充当前用户 其实还是有安全隐患的 你要知道在web领域没有绝对的安全也没有绝对的不安全 """ cookie 服务端保存在客户端浏览器上的信息都可以称之为cookie 它的表现形式一般都是k:v键值对(可以有多个) session 数据是保存在服务端的并且它的表现形式一般也是k:v键值对(可以有多个) 下述内容暂时了解即可 先给我搞明白最简单的cookie与session使用再说话! 还想了解见:https://www.cnblogs.com/Dominic-Ji/p/10886902.html token session虽然数据是保存在服务端的 但是禁不住数据量大 服务端不再保存数据 登陆成功之后 将一段用户信息进行加密处理(加密算法之后你公司开发知道) 将加密之后的结果拼接在信息后面 整体返回给浏览器保存 浏览器下次访问的时候带着该信息 服务端自动切去前面一段信息再次使用自己的加密算法 跟浏览器尾部的密文进行比对 jwt认证 三段信息 (后期会讲 结合django一起使用) 总结: 1.cookie就是保存在客户端浏览器上的信息 2.session就是保存在服务端上的信息 3.session是基于cookie工作的(其实大部分的保存用户状态的操作都需要使用到cookie)
cooike
1 ''' 2 cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是 3 浏览器实现的一种数据存储功能。 4 5 cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的 6 文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在 7 客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据 8 太多磁盘空间,所以每个域的cookie数量是有限的。 9 '''
session
1 ''' 2 session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和 3 你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。 4 5 session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分, 6 服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的 7 时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么 8 保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 9 的方式。 10 11 服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会 12 被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如 13 果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会 14 丢失。
Cookie操作
1 # 虽然cookie是服务端告诉客户端浏览器需要保存内容 2 # 但是客户端浏览器可以选择拒绝保存 如果禁止了 那么 只要是需要记录用户状态的网站登陆功能都无法使用了 3 4 # 视图函数的返回值 5 return HttpResponse() 6 return render() 7 return redirect() 8 9 10 obj1 = HttpResponse() 11 # 操作cookie 12 return obj1 13 14 obj2 = render() 15 # 操作cookie 16 return obj2 17 18 obj3 = redirect() 19 # 操作cookie 20 return obj3 21 # 如果你想要操作cookie,你就不得不利用obj对象 22 23 24 """ 25 设置cookie 26 obj.set_cookie(key,value) 27 获取cookie 28 request.COOKIES.get(key) 29 在设置cookie的时候可以添加一个超时时间 30 obj.set_cookie('username', 'jason666',max_age=3,expires=3) 31 32 max_age 33 expires 34 两者都是设置超时时间的 并且都是以秒为单位 35 需要注意的是 针对IE浏览器需要使用expires 36 主动删除cookie(注销功能) 37 request.delete_cookie('username') 38 39 """ 40 # 我们完成一个真正的登陆功能 41 # 校验用户是否登陆的装饰器 42 """ 43 用户如果在没有登陆的情况下想访问一个需要登陆的页面 44 那么先跳转到登陆页面 当用户输入正确的用户名和密码之后 45 应该跳转到用户之前想要访问的页面去 而不是直接写死 46 """ 47 def login_auth(func): 48 def inner(request,*args,**kwargs): 49 # print(request.path_info) 50 # print(request.get_full_path()) # 能够获取到用户上一次想要访问的url 51 target_url = request.get_full_path() 52 if request.COOKIES.get('username'): 53 return func(request,*args,**kwargs) 54 else: 55 return redirect('/login/?next=%s'%target_url) 56 return inner 57 58 def login(request): 59 if request.method == 'POST': 60 username = request.POST.get('username') 61 password = request.POST.get('password') 62 if username == 'jason' and password == '123': 63 64 # 获取用户上一次想要访问的url 65 target_url = request.GET.get('next') # 这个结果可能是None 66 if target_url: 67 obj = redirect(target_url) 68 else: 69 # 保存用户登陆状态 70 obj = redirect('/home/') 71 # 让浏览器记录cookie数据 72 obj.set_cookie('username', 'jason666') 73 """ 74 浏览器不单单会帮你存 75 而且后面每次访问你的时候还会带着它过来 76 """ 77 # 跳转到一个需要用户登陆之后才能看的页面 78 return obj 79 return render(request,'login.html') 80 81 82 @login_auth 83 def home(request): 84 # 获取cookie信息 判断你有没有 85 # if request.COOKIES.get('username') == 'jason666': 86 # return HttpResponse("我是home页面,只有登陆的用户才能进来哟~") 87 # # 没有登陆应该跳转到登陆页面 88 # return redirect('/login/') 89 return HttpResponse("我是home页面,只有登陆的用户才能进来哟~") 90 91 92 @login_auth 93 def logout(request): 94 obj = redirect('/app01/login/') 95 obj.delete_cookie('username') 96 return obj
1 from django.shortcuts import render, HttpResponse, redirect 2 3 # Create your views here. 4 5 from app01 import models 6 7 8 def login_auth(func): 9 def wrapper(request, *args, **kwargs): 10 print(request.path) 11 print(request.path_info) 12 print(request.get_full_path()) 13 target_url = request.get_full_path() 14 if request.COOKIES.get('username'): 15 return func(request, *args, **kwargs) 16 else: 17 return redirect('/app01/login/?next=%s'%target_url) 18 19 return wrapper 20 21 22 @login_auth 23 def home(request): 24 return HttpResponse('欢迎来到app01_home页面') 25 26 27 def login(request): 28 if request.method == 'POST': 29 username = request.POST.get('username') 30 password = request.POST.get('password') 31 if username == 'jason' and password == '123': 32 print(request.GET.get('next')) 33 target_url = request.GET.get('next') 34 if target_url: 35 obj = redirect(target_url) 36 else: 37 obj = redirect('/app01/home/') 38 obj.set_cookie('username', 'jason666') 39 return obj 40 else: 41 return HttpResponse('账号密码错误') 42 return render(request, 'login.html') 43 44 45 @login_auth 46 def logout(request): 47 obj = redirect('/app01/login/') 48 obj.delete_cookie('username') 49 return obj 50 51 52 @login_auth 53 def index(request): 54 return HttpResponse('欢迎来到app01_Index页面')
cookie其他方法及参数
获取Cookie request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) 参数: default: 默认值 salt: 加密盐 max_age: 后台控制过期时间 设置Cookie rep = HttpResponse(...) rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...) 参数: key, 键 value='', 值 max_age=None, 超时时间 expires=None, 超时时间(IE requires expires, so set it if hasn't been already.) path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问 domain=None, Cookie生效的域名 secure=False, https传输 httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖) 删除Cookie def logout(request): rep = redirect("/login/") rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值 return rep
Session操作
1 """ 2 session数据是保存在服务端的(存?),给客户端返回的是一个随机字符串 3 sessionid:随机字符串 4 5 1.在默认情况下操作session的时候需要django默认的一张django_session表 6 数据库迁移命令 7 django会自己创建很多表 django_session就是其中的一张 8 9 10 django默认session的过期时间是14天 11 但是你也可以人为的修改它 12 13 14 设置session 15 request.session['key'] = value 16 17 获取session 18 request.session.get('key') 19 20 设置过期时间 21 request.session.set_expiry() 22 括号内可以放四种类型的参数 23 1.整数 多少秒 24 2.日期对象 到指定日期就失效 25 3.0 一旦当前浏览器窗口关闭立刻失效 26 4.不写 失效时间就取决于django内部全局session默认的失效时间 27 28 清除session 29 request.session.delete() # 只删服务端的 客户端的不删 30 request.session.flush() # 浏览器和服务端都清空(推荐使用) 31 32 33 session是保存在服务端的 但是session的保存位置可以有多种选择 34 1.MySQL 35 2.文件 36 3.redis 37 4.memcache 38 ... 39 40 41 django_session表中的数据条数是取决于浏览器的 42 同一个计算机上(IP地址)同一个浏览器只会有一条数据生效 43 (当session过期的时候可能会出现多条数据对应一个浏览器,但是该现象不会持续很久,内部会自动识别过期的数据清除 你也可以通过代码清除) 44 45 主要是为了节省服务端数据库资源 46 """ 47 48 request.session['hobby'] = 'girl' 49 """ 50 内部发送了那些事 51 1.django内部会自动帮你生成一个随机字符串 52 2.django内部自动将随机字符串和对应的数据存储到django_session表中 53 2.1先在内存中产生操作数据的缓存 54 2.2在响应结果django中间件的时候才真正的操作数据库 55 3.将产生的随机字符串返回给客户端浏览器保存 56 """ 57 request.session.get('hobby') 58 """ 59 内部发送了那些事 60 1.自动从浏览器请求中获取sessionid对应的随机字符串 61 2.拿着该随机字符串去django_session表中查找对应的数据 62 3. 63 如果比对上了 则将对应的数据取出并以字典的形式封装到request.session中 64 如果比对不上 则request.session.get()返回的是None 65 """ 66 67 68 # 利用session实现登陆验证
1 from django.shortcuts import render, HttpResponse, redirect 2 3 4 # Create your views here. 5 6 7 def login_auth(func): 8 def wrapper(request, *args, **kwargs): 9 target_url = request.get_full_path() 10 if request.session.get('jason'): 11 return func(request, *args, **kwargs) 12 else: 13 return redirect('/app02/login/?next=%s'%target_url) 14 15 return wrapper 16 17 18 def login(request): 19 if request.method == 'POST': 20 username = request.POST.get('username') 21 password = request.POST.get('password') 22 if username == 'jason' and password == '123': 23 target_url = request.GET.get('next') 24 if target_url: 25 obj = redirect(target_url) 26 else: 27 obj = redirect('/app02/home/') 28 request.session['jason'] = 'haha6666' 29 request.session.set_expiry(30) 30 return obj 31 else: 32 HttpResponse('账号或密码错误') 33 return render(request, 'login.html') 34 35 36 @login_auth 37 def home(request): 38 return HttpResponse('欢迎来到app_02home页面') 39 40 41 @login_auth 42 def index(request): 43 return HttpResponse('欢迎来到app_02index页面') 44 45 46 @login_auth 47 def logout(request): 48 request.session.flush() 49 return redirect('/app02/login/')
django中的session方法
# 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 会话session的key request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查会话session的key在数据库中是否存在 request.session.exists("session_key") # 删除当前会话的所有Session数据 request.session.delete() # 删除当前的会话数据并删除会话的Cookie。 request.session.flush() 这用于确保前面的会话数据不可以再次被用户的浏览器访问 例如,django.contrib.auth.logout() 函数中就会调用它。 # 设置会话Session和Cookie的超时时间 request.session.set_expiry(value) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。
django中的session配置
1. 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) 2. 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 3. 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 4. 缓存+数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 5. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 其他公用设置项: SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
CBV如何添加装饰器
1 from django.views import View 2 from django.utils.decorators import method_decorator 3 """ 4 CBV中django不建议你直接给类的方法加装饰器 5 无论该装饰器能都正常给你 都不建议直接加 6 """ 7 8 # @method_decorator(login_auth,name='get') # 方式2(可以添加多个针对不同的方法加不同的装饰器) 9 # @method_decorator(login_auth,name='post') 10 class MyLogin(View): 11 @method_decorator(login_auth) # 方式3:它会直接作用于当前类里面的所有的方法 12 def dispatch(self, request, *args, **kwargs): 13 return super().dispatch(request,*args,**kwargs) 14 # @method_decorator(login_auth) # 方式1:指名道姓 15 def get(self,request): 16 return HttpResponse("get请求") 17 18 def post(self,request): 19 return HttpResponse('post请求')
今日测验
1 """ 2 1.什么是cookie和session,你能描述一下它们的由来和工作机制吗(切勿糊弄,敷衍了事) 3 2.django中如何操作cookie和session,请写出尽量多的操作方法,并针对session的操作 4 方法详细内部发生的事情,django默认的session失效时间是多久(切勿糊弄,敷衍了事) 5 3.面相对象中的__init__和__new__的区别是什么,利用__new__可以实现什么 6 4.如何给CBV添加装饰器,列举你所知道的几种方式 7 """
今日内容回顾
forms组件源码
1 #入口:form_obj.is_valid() 2 3 # 校验字段和钩子函数的执行 4 5 # 报错提示 其实可以有两种方式(针对局部钩子函数) 6 1.self.add_error() 7 2.raise ValidationError() 8 9 """ 10 python源码里面使用最频繁的其实就是反射 11 """
cookie与session
1 # cookie与session产生原因 2 由于http协议是无状态的 3 4 # cookie概念 5 服务端设置保存在客户端浏览器上的键值对(只要符合前面的定义都可以叫cookie) 6 cookie虽然是服务端设置的但是浏览器可以选择不保存 7 8 # session概念 9 存储在服务端上的键值对(用来标识当前用户) 需要基于cookie才能工作 10 其实大部分的保存状态的实现都需要基于cookie来做 11 12 # 在web领域没有绝对的安全 13 基本上防御措施都需要程序员自己写代码完善,并且之内完善没法杜绝
django操作cookie
1 # 需要借助于HttpResponse对象 2 3 # 设置cookie 4 obj.set_cookie(key,value) 5 # 超时时间 6 obj.set_cookie(key,value,max_age/expires) 7 expires 针对IE需要用这个参数 数字是以秒为单位 8 # 加盐 9 obj.set_signed_cookie(key,value,salt='盐') 10 # 获取 11 request.COOKIES.get(key) 12 request.get_signed_cookie(key,salt='盐') 13 # 删除 14 obj.delete_cookie(key) 15 16 """ 17 校验用户是否登陆才能访问视图函数的装饰器 18 能够记录用户在没有登陆之前想要访问的页面,登陆之后跳转到对应的页面 19 request.path 20 request.path_info 21 request.get_full_path() 22 """
django操作session
1 """ 2 1.session是存储在服务端的 django默认情况下是需要借助于django_session表 3 来存储数据 也就意味着如果你想要操作session那么必须先执行数据库迁移命令让 4 django先把django_session表创建出来(no such table:django_session) 5 6 2.django默认的session过期时间是14天 7 8 3.session存储在服务端 可以有很多地方存储 9 1.表 10 2.文件 11 3.缓存 12 4.其他 13 ... 14 """ 15 # 设置 16 request.session[key] = value 17 """ 18 三件事 19 """ 20 # 获取 21 request.session.get(key) 22 """ 23 三件事 24 """ 25 # 删除 26 request.session.delete() 27 request.session.flush() 28 # 设置超时时间 29 request.session.set_expiry() 30 1.数字 秒数 31 2.datetime/timedelta格式 日期格式 32 3.None 参加全局失效策略 33 4.0 窗口关闭即失效 34 35 """ 36 基于session实现用户登陆 37 38 有时候如果多个视图函数都需要使用到一些数据的话,你也可以考虑将该数据存储到django_session表中,方便后续的使用 39 eg: 40 登陆验证码(bbs作业会涉及到) 41 """
CBV如何添加装饰器
1 """ 2 django针对CBV添加装饰器需要你导入一个模块 3 """ 4 from django.utils.decorators import method_decorator 5 6 # 第一种 7 class MyCBV(View): 8 def get(self,request): 9 return HttpResponse() 10 11 @method_decorator(login_auth) 12 def post(self,request): 13 return HttpResponse() 14 15 # 第二种 16 @method_decorator(login_auth,name='post') 17 @method_decorator(index_de,name='get') 18 class MyCBV(View): 19 def get(self,request): 20 return HttpResponse() 21 22 def post(self,request): 23 return HttpResponse() 24 25 # 第三种 26 class MyCBV(View): 27 @method_decorator(login_auth) 28 def dispatch(self,request,*args,**kwargs): 29 """ 30 看CBV源码可以得出 CBV里面所有的方法在执行之前都需要先经过 31 dispatch方法(该方法你可以看成是一个分发方法) 32 """ 33 return super().dispatch(request,*args,**kwargs) 34 35 def get(self,request): 36 return HttpResponse() 37 38 def post(self,request): 39 return HttpResponse()
作业
""" 1.整理今日内容到博客 2.利用session实现登陆验证 3.复习django阶段所学所有知识点,好好整理回顾(后面没时间了) 4.预习内容: https://www.cnblogs.com/Dominic-Ji/p/10881214.html django中间件 auth模块 """