django之forms组件和cookie与session操作
forms组件
forms主要功能
生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容
注意点:
注册页面: 用户点击注册发送到后端做用户名密码的校验。 用户不能含敏感词,不符合社会主义核心价值观。 密码不能为空。
需求:
我们写一个注册页面 获取用户输入的用户名和密码 用户点击注册发送到后端做用户名密码的校验 用户名中不能包含京瓶梅 不符合社会主义核心价值观 密码不能为空 你个DSB,密码怎么能为空 1.手写获取用户输入的前端页面代码 渲染页面 2.后端获取用户数据并做合法性校验 校验数据 3.将校验之后的结果渲染到前端页面 展示信息
普通方式手写注册功能
views.py
# 注册 def register(request): error_msg = "" if request.method == "POST": username = request.POST.get("name") pwd = request.POST.get("pwd") # 对注册信息做校验 if len(username) < 6: # 用户长度小于6位 error_msg = "用户名长度不能小于6位" else: # 将用户名和密码存到数据库 return HttpResponse("注册成功") return render(request, "register.html", {"error_msg": error_msg})
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册页面</title> </head> <body> <form action="/reg/" method="post"> {% csrf_token %} <p> 用户名: <input type="text" name="name"> </p> <p> 密码: <input type="password" name="pwd"> </p> <p> <input type="submit" value="注册"> <p style="color: red">{{ error_msg }}</p> </p> </form> </body> </html>
forms组件
1.渲染页面 2.校验数据 3.展示信息
先定义一个类和导入:
from django import forms
from django import forms class MyRegForm(forms.Form): # 用户名最少3位最多8位 username = forms.CharField(max_length=8,min_length=3) password = forms.CharField(max_length=8,min_length=3) # email字段必须填写符合邮箱格式的数据 email = forms.EmailField()
如何校验数据
# 1.传入待校验的数据 用自己写的类 传入字典格式的待校验的数据 form_obj = views.MyRegForm({'username':'jason','password':'12','email':'123456'}) # 2.判断数据是否符合校验规则 form_obj.is_valid() # 该方法只有在所有的数据全部符合校验规则才会返回True False # 3.如何获取校验之后通过的数据 form_obj.cleaned_data {'username': 'jason'} # 4.如何获取校验失败及失败的原因 form_obj.errors { 'password': ['Ensure this value has at least 3 characters (it has 2).'], 'email': ['Enter a valid email address.'] } # 5.注意 forms组件默认所有的字段都必须传值 也就意味着传少了是肯定不行的 而传多了则没有任何关系 只校验类里面写的字段 多传的直接忽略了 form_obj = views.MyRegForm({'username':'jason','password':'123456'}) form_obj.is_valid() Out[12]: False form_obj.errors Out[18]: {'email': ['This field is required.']} form_obj = views.MyRegForm({'username':'jason','password':'123456',"email":'123@qq.com',"hobby":'hahahaha'}) form_obj.is_valid() Out[14]: True form_obj.cleaned_data Out[15]: {'username': 'jason', 'password': '123456', 'email': '123@qq.com'} form_obj.errors Out[16]: {}
如何渲染页面的三种方法
先定义一个类: forms组件只帮你渲染获取用户输入(输入 选择 下拉 文件)的标签 不渲染按钮和form表单标签,渲染出来的每一个input提示信息都是类中字段首字母大写。
第一种方法:
优点:
多个p标签,本地测试方便。
缺点:
封装程度太高了 不便于扩展
<p>第一种渲染方式:多个p标签 本地测试方便 封装程度太高了 不便于扩展</p> {{ form_obj.as_p }} {{ form_obj.as_ul }} {{ form_obj.as_table }}
效果:
第二种方法:
优点:
扩展性较高 书写较为繁琐
<p>第二种渲染方式: 扩展性较高 书写较为繁琐</p> <label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label> {{ form_obj.username }} {{ form_obj.password.label }}{{ form_obj.password }} {{ form_obj.email.label }}{{ form_obj.email }}
效果:
第三种方法:推荐使用
优点:
使用效率高,减少代码冗余
<p>第三种渲染方式 推荐使用</p> {% for form in form_obj %} <p> {{ form.label }}{{ form }}</p> {% endfor %}
效果:
如何渲染错误信息
导入:
from django.shortcuts import render,HttpResponse,redirect
前端:
<form action="" method="post" novalidate> {% for form in form_obj %} <p> {{ form.label }}{{ form }} <span>{{ form.errors.0 }}</span> # 这个是模板语法 索引不会出现超出报错 </p> {% endfor %} <input type="submit"> </form>
后端:
def reg(request): # 1 先生成一个空的类对象 form_obj = MyRegForm() if request.method == 'POST': # 3 获取用户数据并交给forms组件校验 request.POST form_obj = MyRegForm(request.POST) # 4 获取校验结果 if form_obj.is_valid(): return HttpResponse('数据没问题') else: # 5 获取校验失败的字段和提示信息 print(form_obj.errors) # 2 直接将该对象传给前端页面 return render(request,'reg.html',locals())
固定错误信息是一个列表,索引取0的位置
label 将英文修改成中文
效果:(用户名:最长8位 不然报错)
校验:邮箱格式是否正确
效果:
forms的常用参数
label input的提示信息 error_messages 自定义报错的提示信息 required 设置字段是否允许为空 initial 设置默认值 widget 控制type类型及属性 widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2'}) widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
导入:
from django.forms import widgets
widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2'}) widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
钩子函数:
# 如果你想同时操作多个字段的数据你就用全局钩子 # 如果你想操作单个字段的数据 你就用局部钩子
全局钩子
针对多个字段
校验两次密码是否一直
# 全局钩子 def clean(self): # 校验密码和确认密码是否一致 password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if not password == confirm_password: # 展示提示信息 self.add_error('confirm_password','两次密码不一致') return self.cleaned_data
效果:
局部钩子
针对单个字段
# 局部钩子 def clean_username(self): username = self.cleaned_data.get('username') if '666' in username: self.add_error('username','光喊666是不行的') return username # 如果你想同时操作多个字段的数据你就用全局钩子 # 如果你想操作单个字段的数据 你就用局部钩子
校验用户名中不能包含666
正则简单用法:
导入:
from django.core.validators import RegexValidator
正则校验 phone = forms.CharField( validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头') ] )
基于使用form组件实现注册功能
views.py
先定义好一个RegForm类:
导入:from django import forms # 按照Django form组件的要求自己写一个类 class RegForm(forms.Form): name = forms.CharField(label="用户名") pwd = forms.CharField(label="密码")
写一个视图函数
# 使用form组件实现注册方式 def register2(request): form_obj = RegForm() if request.method == "POST": # 实例化form对象的时候,把post提交过来的数据直接传进去 form_obj = RegForm(request.POST) # 调用form_obj校验数据的方法 if form_obj.is_valid(): return HttpResponse("注册成功") return render(request, "register2.html", {"form_obj": form_obj})
login2.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册2</title> </head> <body> <form action="/reg2/" method="post" novalidate autocomplete="off"> {% csrf_token %} <div> <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label> {{ form_obj.name }} {{ form_obj.name.errors.0 }} </div> <div> <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label> {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }} </div> <div> <input type="submit" class="btn btn-success" value="注册"> </div> </form> </body> </html>
forms实现的网页效果的功能:
• 前端页面是form类的对象生成的 -->生成HTML标签功能 • 当用户名和密码输入为空或输错之后 页面都会提示 -->用户提交校验功能 • 当用户输错之后 再次输入 上次的内容还保留在input框 -->保留上次输入内容
cookie与session操作
Cookie的介绍
当你第一次登陆成功之后 服务端给你返回了一个随机字符串 保存客户端浏览器上 之后再次朝服务端发请求 只需要携带该随机字符串 服务端就能够识别当前用户身份 超时时间的概念 cookie虽然是保存在客户端的浏览器上的 但是是服务端设置的 浏览器也是可以拒绝服务端对要求 不保存cookie
什么是Cookie
Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
Cookie的原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
查看Cookie
我们使用Chrome浏览器,打开开发者工具。
Django中操作Cookie
Cookie
获取Cookie
request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
保存在客户端浏览器上的键值对
cookie 保存在客户端浏览器上的键值对 return HttpResponse('...') return render(...) return redirect(...) # 变形 obj = HttpResponse('...') return obj obj1 = render(...) return obj1 obj2 = redirect(...) 设置cookie obj.set_cookie() 获取cookie request.COOKIES.get() 删除cookie obj.delete_cookie()
# 装饰器模板 from functools import wraps def login_auth(func): @wraps(func) def inner(request,*args,**kwargs): # print('request.path_info:',request.path_info) # print('request.get_full_path():',request.get_full_path()) # 执行被装饰函数之前你可以做的事情 target_url = request.path_info if request.COOKIES.get('username'): res = func(request,*args,**kwargs) return res else: return redirect('/login/?next=%s'%target_url) return inner
print('request.path_info:',request.path_info) # 只拿路径部分 不拿参数 print('request.get_full_path():',request.get_full_path()) # 路径加参数 request.path_info: /home/ request.get_full_path(): /home/?username=jason&password=123
Session
Cookie 支持字节相对session少,本身保存在客户端,可能被拦截或窃取 能支持更多的字节,保存在服务器,有较高的安全性
总结:
Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
保存在服务端上的键值对
设置:
request.session['key'] = value
1.django内部会自动生成一个随机字符串 2.去django_session表中存储数据 键就是随机字符串 值是要保存的数据(中间件干的) 3.将生成好的随机字符串返回给客户端浏览器 浏览器保存键值对 sessionid 随机字符串
获取
request.session.get('key')
1.django会自动取浏览器的cookie查找sessionid键值对 获取随机字符串 2.拿着该随机字符串取django_session表中比对数据 3.如果比对上了 就将随机字符串对应的数据获取出来并封装到request.session供用户调用
django中默认的session超时时间为14天
设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。
删除当前会话的所有Session数
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问 例如,django.contrib.auth.logout() 函数中就会调用它。 session是保存在服务端
验证以上cookie和session的代码
装饰器模板 views.py
from functools import wraps def login_auth(func): @wraps(func) def inner(request,*args,**kwargs): # print('request.path_info:',request.path_info) # print('request.get_full_path():',request.get_full_path()) # 执行被装饰函数之前你可以做的事情 target_url = request.path_info if request.COOKIES.get('username'): res = func(request,*args,**kwargs) return res else: return redirect('/login/?next=%s'%target_url) return inner
登录功能 views.py
def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'jason' and password == '123': # target_url = request.GET.get("next",'/home/') target_url = request.GET.get("next") # 判断用户登录之前是否有想要访问的url if target_url: # 保存用户登录状态 obj = redirect(target_url) else: obj = redirect('/home/') # 设置cookie obj.set_cookie('username','jason666',max_age=3) return obj return render(request,'login.html')
校验浏览器是否有对应的cookie
@login_auth def home(request): # 校验浏览器是否有对应的cookie # if request.COOKIES.get('username'): # print(request.COOKIES) # return HttpResponse("我是home页面 只有登录的用户才能访问") # else: # return redirect('/login/') return HttpResponse("我是home页面 只有登录的用户才能访问")
@login_auth def index(request): return HttpResponse('我是index页面 只有登录之后的用户才能看')
@login_auth def demo(request): return HttpResponse('我是demo页面 只有登录之后的用户才能看')
@login_auth def logout(request): obj = HttpResponse('注销了') obj.delete_cookie('username') return obj
def set_session(request): # request.session['username'] = 'egondsb' request.session['name'] = 'egon' # request.session.set_expiry(5) return HttpResponse("set_session")
def get_session(request): # print(request.session) # <django.contrib.sessions.backends.db.SessionStore object at 0x00000259F72683C8> print(request.session.get('name')) return HttpResponse("get_session")
def del_session(request): request.session.flush() return HttpResponse('注销了')
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^login/',views.login), url(r'^home/',views.home), url(r'^index/',views.index), url(r'^demo/',views.demo), url(r'^logout/',views.logout), url(r'^set_session/',views.set_session), url(r'^get_session/',views.get_session), url(r'^del_session/',views.del_session), ]
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <form action="" method="post"> <p>username:<input type="text" name="username"></p> <p>password:<input type="text" name="password"></p> <input type="submit"> </form> </body> </html>
来源:https://www.cnblogs.com/WQ577098649/p/12189971.html