forms组件源码分析
# 从form_obj.is_valid()开始进去源码观看
def is_valid(self):
return self.is_bound and not self.errors
如果要是向from_obj内部传值的话,那么is_bound则肯定为true,而self.errors则是forms组件中传值不符合规矩的则会传入errors中。
# 进入self.errors中查看
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
如果没有出错的话,会执行full_clean方法
# 进入full_clean
def full_clean(self):
# 中间省略几个判断
self._clean_fields() # 校验字段 + 局部钩子,内部使用拼接和反射实现的
self._clean_form() # 全局钩子
self._post_clean()
基本上forms组件的所有功能都是处于这个方法。
cookie与session
'''
cookie:登陆之后,将用户的状态保存到浏览器的本地状态中,之后访问的时候会自动将该状态信息发送给服务端来进行校验。
session:当用户登陆之后,服务端随机生成一个字符串,返回给浏览器保存,下次浏览器再来访问的时候,会携带者随机字符串,服务端会拿去进去对比用户信息。
token:登录成功之后,将一段用户信息进行加密处理,加密结果拼接在信息后面,整体返回给浏览器保存,下次再来登陆的时候就会携带者该信息,服务器会拿走前面的信息再次使用自己的算法对浏览器尾部的密文进行对比。
总结:
1. cookie就是保存在客户端浏览器的信息
2. session就是保存在客户端的信息。
3. session是基于cookie工作的。
'''
Cookie操作
# cookie是浏览器保存的内容 一旦浏览器设置为不保存cookie,那么一些记录用户状态的网站就不能进行登陆了。
# 操作cookie和普通的视图含有那么一丢丢不一样,是先生成对象,然后基于对象进行cookie操作,在返回给前端。
普通视图函数
return HttpResponse()
return render()
return redirect
cookie操作
obj = HttpResponse() # 同render,redirect
# 在这个位置执行一些cookie操作
return obj
# 设置cookie
obj.set_cookie(key,value)
# 从请求中获取cookie
request.COOKIES.get(key)
# 设置cookie的时候还可以添加一个超时时间
obj.set_cookie('username','123',max_age=3,expires=3)
max_age:设置时间,秒为单位
expires:设置时间,秒为单位,支持IE
# 主动删除cookie使用注销的功能。
obj.delete_cookie(key)
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep
# 需要先登录,然后才能到主页面,再次来的时候验证cookie中的信息
def index(request):
if request.COOKIES.get('username') == 'tom':
return render(request, 'app03_index.html')
return redirect('app03_login')
# 登陆并制作cookie,
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'tom' and password == '123':
obj = redirect('app03_index')
obj.set_cookie('username', 'tom')
obj.set_cookie('password', '123')
return obj
return render(request, 'login.html')
session操作
'''
在执行数据库迁移命令的时候,会有那么一张表:django_session。
这一张表就是存放返回给浏览器的特殊字符串的意义锁代表的用户状态。
默认有效期为14天。
针对session,可以把它当作一个字典进行操作
request.session['key'] = value 设置session
request.session.get('key') 获取session
request.session.set_expiry() 设置过期时间
括号内有四种参数:
1.整数:单位是秒
2.日期对象:到指定日期就过期
3.0:一旦当前浏览器窗口关闭就立刻失效
4.不写:默认时间:14天。
清除session
request.session.delete() # 只删除服务端的,客户端的不删除
request.session.flush() # 浏览器和服务端的都清空(推荐使用这种方法)
session的保存位置可以有很多种
1. Mysql
2.文件
3.redis
4.memcache
...
django_session中的数据条数是取决于浏览器的,每一个计算机(ip)地址的同一个浏览器只有一条数据生效,当过期的时候内部会自动进行清除。
'''
request.session['username'] = 'tom'
这个设置的过程内部都发生了什么:
1. django 内部会自动生成一个随机字符串
2. django内部自动将随机字符串和对应的数据存放到django_session表中
2.1 现在内存中产生操作数据的缓存
2.2 在响应结果gjango中间件的时候,才真正的操作数据库
3. 将产生的随机字符返回给客户端保存。
request.session.get('username')
这个获取过程内部发生了什么:
1. 自动从浏览器请求中获取sessionid对应的随机字符串
2. 拿着该随机字符串去django_session中查找对应的数据
3.
1.比对成功,将对应的数据存成字典的形式放到session中
2.比对不上,返回的是None。
# 主页面需要首先验证session部分
def index(request):
if request.session.get('username'):
return render(request, 'app03_index.html')
return redirect('app03_login')
# 登陆完毕之后就将信息保存到session状态中
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'tom' and password == '123':
request.session['username'] = 'tom'
request.session['password'] = '123'
return redirect(reverse('app03_index'))
return render(request, 'login.html')
总结:在验证登录的时候,可以写一个装饰器,将所有需要登陆的页面都添加这个装饰器,在登录完毕之后,在返回到登陆之前的页面。
def login_auth(func):
def inner(request,*args,**kwargs):
# print(request.path_info)
# print(request.get_full_path()) # 能够获取到用户上一次想要访问的url
target_url = request.get_full_path()
if request.COOKIES.get('username'):
return func(request,*args,**kwargs)
else:
return redirect('/login/?next=%s'%target_url)
return inner
CBV如何添加装饰器
'''
视图层中,要给类视图添加装饰器,django是不推荐这么给类的方法加装饰器的,但也是可以加的
'''
from django.views import View
from django.utils.decorators import method_decorator
@method_decorator(装饰器, name='post') # 方式2 针对不同的方法可添加多个
class Mylogin(View):
def dispatch(self, request, *args, **kwargs):
# 方式3: 此处可以规定操作,会作用与所有的方法
return supre().dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, 'login.html')
@method_decorator('装饰器的名字') # 第一种方法:指名道姓
def post(self, request):
return render(request, 'index.html')