Cookie的由来:
因为HTTP协议是无状态;无状态也就是每次的请求都是独立的,比如你不用登录你的账户,你就可以进入需要账户的网站一样,因为对于服务器来说,每次请求都是全新的;
状态也可以理解为B和S之间的通信产生的数据;无状态则表示数据不会被保留;但是在某些场合下,我们是需要用到这些数据;因此我们需要保持状态,所以cookie就产生了;
Django中操作Cookie:
获取Cookie
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
# cookie装饰器
# def crwapper(func):
# @wraps(func)
# def inner(request,*args,**kwargs): #被装饰器装饰的函数的参数;一个形参
# ret = request.get_signed_cookie("is_login", default="0", salt='加盐')
# if ret == "4":
# ret_new = func(request)
# return ret_new
# else:
# path = request.path_info #获得当前的路径;不带条件
# request.get_full_path()
# print(path)
# return redirect("/login/?next={}".format(path))
# return inner
参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间
设置Cookie:
rep = HttpResponse(...)
rep = render(request, ...)
rep = redirect(...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
注意:设置cookie的时候是用响应来设置
- key, 键
- value='', 值
- max_age=None, 超时时间
rep.set_signed_cookie("is_login","4",salt='加盐',max_age =10) #max_age 为cookie存在的秒数
删除Cookie:
ef logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep
Cookie版登陆校验:
# cookie版
# def login(request):
# # GET请求就是请求获取页面;或是搜索引擎
# # username_list=[]
# # pwd_list = []
# error_msg=""
# if request.method == "POST":
# # 否则的话就是POST请求,是提交表单等数据给服务器;request.POST获得请求的数据
# ret = request.POST
# username = ret.get("username", None)
# password = ret.get("pwd", None)
#
# # 把/login/?next=/index/ 条件拿到
#
# path =request.get_full_path() #获得路径 加 条件;
# print(path) #/login/?next=/index/
# url = request.GET.get("next") #动态的路径
#
# # obj = models.UserInfo.objects.all()
# # for i in obj:
# # username_list.append(i.name)
# # pwd_list.append(i.password)
# # if username in username_list and password in pwd_list:
# if username=="alex" and password=="123":
# # return HttpResponse("登录成功")
# # 给浏览器发送一个响应,带cookie
# if url:
# rep = redirect(url) #响应的对象
# else:
# rep = redirect("/login_home/") # 响应的对象
# # rep.set_cookie("is_login","1")
# rep.set_signed_cookie("is_login","4",salt='加盐',max_age =10) #max_age 为cookie存在的秒数
# # return redirect("http://www.baidu.com")
# return rep
# else:
# error_msg="账号或者密码错误"
# #动态网页,替换的功能
# return render(request, 'login.html',{"error":error_msg})
Session
由于cookie本身是保存在客户端上的(也就是浏览器上的),容易被拦截或窃取;同时最大只能支持4096个字节;
所以出现了Session,Session是保存在服务器端的,有较高的安全性,但是基于HTTP协议的无状态的特性,要用Cookie起到桥接的作用;
因此 现在多用 Session 和 Cookie 结合使用;Cookie和Session其实是共通性的东西,不限于语言和框架
其实 存 和 取 是很简单的,生成随机的字符串,然后把字符串当作K,存的数据作为一个大字典;按照 键值对的形式保存在数据库中;然后 把随机的字符串当作cookie返回给浏览器;这系列的过程全部由Django帮你做;你只需要存和取就行了
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失效策略。
Session 和 cookie 结合的登录校验
# session和cookie结合版的
def login(request):
# GET请求就是请求获取页面;或是搜索引擎
# username_list=[]
# pwd_list = []
# 将所有的session 失效日期 小于当前的日期的数据 删除;也就是将过期的数据删除;
request.session.clear_expired()
error_msg = ""
if request.method == "POST":
# 否则的话就是POST请求,是提交表单等数据给服务器;request.POST获得请求的数据
ret = request.POST
username = ret.get("username", None)
password = ret.get("pwd", None)
# 把/login/?next=/index/ 条件拿到
path = request.get_full_path() # 获得路径 加 条件;
print(path) # /login/?next=/index/
url = request.GET.get("next") # 动态的路径
# obj = models.UserInfo.objects.all()
# for i in obj:
# username_list.append(i.name)
# pwd_list.append(i.password)
# if username in username_list and password in pwd_list:
if username == "alex" and password == "123":
# return HttpResponse("登录成功")
# 给浏览器发送一个响应,带cookie
if url:
rep = redirect(url) # 响应的对象
else:
rep = redirect("/login_home/") # 响应的对象
# 设置一下 session ,生成一段字符串,然后把字符串当做K,
# 把存的数据放在大字典里面,大字典当做v,按K-V的形式保存在数据库里面;
# Django自动的;帮你生成一段字符串;按K-V的形式保存在数据库里面;
request.session["is_login"] = "1"
# Object of type 'datetime' is not JSON serializable;需要自定义的序列化
# day_time = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) + datetime.timedelta(days=3)
# request.session.set_expiry(day_time)
request.session.set_expiry(7 * 24 * 60 * 60) # 7s后session失效;失效是指浏览器上的cookie没有了,但是数据库里面还有;
return rep
else:
error_msg = "账号或者密码错误"
# 动态网页,替换的功能
return render(request, 'login.html', {"error": error_msg})
# session和cookie装饰器
def crwapper(func):
@wraps(func)
def inner(request, *args, **kwargs): # 被装饰器装饰的函数的参数;一个形参
ret = request.session.get("is_login", None)
if ret == "1":
ret_new = func(request)
return ret_new
else:
path = request.path_info # 获得当前的路径;不带条件
request.get_full_path()
print(path)
return redirect("/login/?next={}".format(path))
return inner
注销Session和Cookie
# 注销cookie和session
def logout(requset):
requset.session.flush()
return redirect('/login/')
Session流程解析
CBV中加装饰器相关:(详细点我)
1. 加在CBV视图的get或post方法上
3. 直接加在视图类上,但method_decorator必须传 name 关键字参数
如果get方法和post方法都需要登录校验的话就写两个装饰器。
# 把上面的session装饰器叫到CBV视图上的方法上
from django.utils.decorators import method_decorator
from django.views import View
# @method_decorator(crwapper,name='post')
class Login(View):
@method_decorator(crwapper) # method_decorator实际上就是把第二个参数request传入你的装饰器的作用;
def post(self, request):
# 否则的话就是POST请求,是提交表单等数据给服务器;request.POST获得请求的数据
ret = request.POST
username = ret.get("username", None)
password = ret.get("pwd", None)
# 把/login/?next=/index/ 条件(参数)拿到
path = request.get_full_path() # 获得路径 加 条件(参数);
# request.path_info 获取路径
print(path) # /login/?next=/index/
url = request.GET.get("next") # 动态的路径
# obj = models.UserInfo.objects.all()
# for i in obj:
# username_list.append(i.name)
# pwd_list.append(i.password)
# if username in username_list and password in pwd_list:
if username == "alex" and password == "123":
# return HttpResponse("登录成功")
# 给浏览器发送一个响应,带cookie
if url:
rep = redirect(url) # 响应的对象
else:
rep = redirect("/login_home/") # 响应的对象
# 设置一下 session ,生成一段字符串,然后把字符串当做K,
# 把存的数据放在大字典里面,大字典当做v,按K-V的形式保存在数据库里面;
# Django自动的;帮你生成一段字符串;按K-V的形式保存在数据库里面;
request.session["is_login"] = "1"
# Object of type 'datetime' is not JSON serializable;需要自定义的序列化
# day_time = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) + datetime.timedelta(days=3)
# request.session.set_expiry(day_time)
request.session.set_expiry(7 * 24 * 60 * 60) # 7s后session失效;失效是指浏览器上的cookie没有了,但是数据库里面还有;
return rep
@method_decorator(crwapper)
def get(self, request):
request.session.clear_expired()
return render(request, 'login.html')
自定义分页:
# 分页
# # 获取当前的页码
# page_num = request.GET.get('page')
# page_num = int(page_num)
# print(page_num)
#
# #获得总的数据
#
# total_num = models.Book.objects.all().count()
#
# #每一页呈现的数量
# each_page = 10
#
# #获得总页码
# total_page,n = divmod(total_num,each_page) # 13//2 --> (6,1)
# if n:
# total_page+=1
#
# # 页面上总共展示多少页码
# max_page = 9
#
# # 在页面张展示的页码 小于 页面上总共展示多少页码数的时候:
# if total_page <= max_page:
# max_page = total_page
#
# # 最大的一半的页码数
# half_max_page = max_page // 2
#
# page_start = page_num - half_max_page
# page_end = page_num + half_max_page
# # 当开始页 小于1 :
# if page_start <=1:
# page_start = 1
# page_end = max_page
# # 当最后一页 大于 总页数的时候 :
# if page_end >=total_page:
# page_end = total_page
# page_start = page_end - max_page +1
#
#
# #每一页呈现的数据 的开始和结束
# data_start = (page_num-1) * each_page
# data_end = page_num * each_page
#
#
# #这个是每一页呈现的数据
# #左闭右开的
# books = models.Book.objects.all()[data_start:data_end]
#
# #在页面张展示的页码
# total_page_html = []
#
# # 首页
# start_page_html = '<li><a href="/see_book/?page=1">{}</a></li>'.format('首页')
# total_page_html.append(start_page_html)
# # 上一页
# if page_num <= 1:
# Previous_page = '<li class="disabled"><a href="#"><span aria-hidden="true">上一页</span></a></li>'
# else:
# Previous_page = '<li><a href="/see_book/?page={}"><span aria-hidden="true">上一页</span></a></li>'.format(page_num-1)
# print(page_num-1)
# total_page_html.append(Previous_page)
#
# for i in range(page_start,page_end+1):
# if i ==page_num:
# page_html = '<li class="active"><a href="/see_book/?page={0}">{0}</a></li>'.format(i)
# else:
# page_html = '<li><a href="/see_book/?page={0}">{0}</a></li>'.format(i)
# total_page_html.append(page_html)
#
# #向下一页
# if page_num >= total_page:
# Next_page = '<li class="disabled"><a href="#"><span aria-hidden="true">下一页</span></a></li>'.format(total_page)
# else:
# Next_page = '<li><a href="/see_book/?page={}"><span aria-hidden="true">下一页</span></a></li>'.format(page_num+1)
# total_page_html.append(Next_page)
#
# #尾页
# end_page_html = '<li><a href="/see_book/?page={1}">{0}</a></li>'.format('尾页',total_page)
# total_page_html.append(end_page_html)
#
# total_page_html = ''.join(total_page_html)