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)