django form组件 Cookie与Session组件
django 之 form组件
<body> <h1>注册页面</h1> <form action="" method="post"> <p>username: <input type="text" name="username"> <span>{{ errors.username }}</span> </p> <p>password: <input type="text" name="password"> <span>{{ errors.password }}</span> </p> <input type="submit"> </form> </body>
def reg(request): errors = {'username':'', 'password':''} if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if 'sb' in username: errors['username'] = '用户名不能有sb' if password == '123': errors['password'] = '密码过于简单,请重新设置' return render(request, 'reg.html', locals())
1. django form组件三个功能
渲染标签
校验数据
展示信息
注意:前端初步校验,可以不做,后端必须校验 !!!
2. 校验数据
第一步:建立form类
第二步:实例化产生form对象
第三步:查看该对象form_obj的信息
form_obj.is_valid() 校验是否有效:所有字段验证通过,返回True
form_obj.errors 错误信息提示:所有未通过校验的字段及错误提示
form_obj.cleaned_data 校验通过的数据
form组件校验数据规则:
从上往下依次取值校验
校验通过的数据,放入cleaned_data
校验未通过数据,放入errors,当全部通过,errors清空
多传入的数据,不会处理
form中所有字段默认必须传值(required=True)
类中字段基本校验全部通过后,需进行进一步的校验:钩子函数
局部钩子函数:单个字段校验
全局钩子函数:多个字段校验
from django.core.exceptions import ValidationError
class MyForm(forms.Form): ..... def clean_name(self): # 局部钩子 name = self.cleaned_data.get('name') if '666' in name:
# 1.主动抛异常
raise ValidationError('光喊666是不行的')
# 2.自定义异常
self.add_error('name', '光喊666是不行的') return name # 为兼容性考虑,加上return 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
前端取消校验:
form标签,添加novalidate属性
右键检查,Elements里面直接修改
3. 渲染标签
from django import forms class MyForm(forms.Form): name = forms.CharField(max_length=6) password = forms.CharField(max_length=8, min_length=3) email = forms.EmailField()
第一种渲染方式:
封装程度高,扩展性差,用于测试方便快捷
def reg(request): form_obj = MyForm() # 生成一个空对象 return render(request, 'reg.html', locals())
<h2>第一种渲染方式</h2> {{ form_obj.as_p }} {{ form_obj.as_ul }}
第二种渲染方式
只渲染获取用户输入的input框,其他提交按钮等需要手动添加
from django import forms class MyForm(forms.Form): name = forms.CharField(max_length=6, label='用户名') password = forms.CharField(max_length=8, min_length=3) email = forms.EmailField() def reg(request): form_obj = MyForm() # 生成一个空对象 return render(request, 'reg.html', locals())
<h2>第二种渲染方式</h2> <form action=""> <p>{{ form_obj.name.label }}{{ form_obj.name }}</p> <p>{{ form_obj.password.label }}{{ form_obj.password }}</p> <p>{{ form_obj.email.label }}{{ form_obj.email }}</p> <input type="submit"> </form>
第三种渲染方式
<h2>第三种渲染方式</h2> <form action=""> {% for foo in form_obj %} <p>{{ foo.label }}{{ foo }}</p> {% endfor %} <input type="submit"> </form>
4. 展示信息
form组件提交数据如果数据不合法,页面上会保留之前用户输入的信息
在使用form组件对模型表进行数据校验的时候,只需要保证字段一致
在创建的对象的时候直接**form_obj.cleaned_data
提示错误信息时:
{{ foo.errors }} 结果为列表,格式为ul
{{ foo.errors.0 }}取出结果,变为正常格式
5. 常用字段
initial 初始值
error_messages 重写错误信息
Password 隐藏input框密码
radioSelect 圆形点,单选,单radio值为字符串
Select 单选框
SelectMultiple 多选框
CheckBox 方形勾,单选
CheckboxSelectMultiple 方形勾,多选
应用实例
from django import forms from django.forms import widgets class MyForm(forms.Form): # 按照form组件写一个类
name = forms.CharField(max_length=6, label='用户名', error_messages={ 'max_length': '用户名最长6位', 'required': '用户名不能为空', }) password = forms.CharField(max_length=8, min_length=3, error_messages={ 'max_length': '密码最长6位', 'min_length': '密码最少3位', 'required': '密码不能为空', }, widget=widgets.PasswordInput(attrs={'class': 'c1 form-control'})) # attrs 设置标签样式 confirm_password = forms.CharField(max_length=8, min_length=3, error_messages={ 'max_length': '确认密码最长6位', 'min_length': '确认密码最少3位', 'required': '确认密码不能为空', }, widget=widgets.PasswordInput(attrs={'class': 'form-control'})) gender = forms.ChoiceField( choices=((1, '男'), (2, '女'), (3, '保密')), label='性别', initial=3, widget=forms.widgets.RadioSelect() ) hobby = forms.ChoiceField( choices=((1, '篮球'), (2, '足球'), (3, '双色球')), label='爱好', initial=3, # 默认值 widget=forms.widgets.Select() # 单选 ) interest = forms.MultipleChoiceField( choices=((1, '看书'), (2, '练字'), (3, '绘画')), label='兴趣', initial=[1, 3], widget=forms.widgets.SelectMultiple() # 多选 ) keep = forms.ChoiceField( label='是否记住密码', initial='checked', widget=forms.widgets.CheckboxInput() ) email = forms.EmailField(error_messages={ 'invalid': '邮箱格式不正确', 'required': '邮箱不能为空' }) keep = forms.ChoiceField( label='是否记住密码', initial='checked', widget=forms.widgets.CheckboxInput() ) def clean_name(self): # 局部钩子 name = self.cleaned_data.get('name') if '666' in name: self.add_error('name', '光喊666是不行的') return name # 为兼容性考虑,加上return 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
# 使用form组件实现注册方式 def reg(request): form_obj = MyForm() # 生成一个空对象 if request.method == 'POST': form_obj = MyForm(request.POST) # 实例化form对象,把post提交的数据直接传入,前后对象名称一致 if form_obj.is_valid(): # 调用form_obj校验数据的方法 models.User.objects.create(**form_obj.cleaned_data) return render(request, 'reg.html', locals())
页面渲染信息
<h2>MyForm</h2> <form action="" method="post" novalidate> {% for foo in form_obj %} <p>{{ foo.label }}{{ foo }}<span>{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit"> </form>
django 操作 Cookie,Session
http协议四大特性
1. 基于TCP/IP作用于应用层的协议
2. 基于请求响应
3. 无状态
4. 无链接
cookie,session 即用于保存客户登录状态
cookie:保存在客户端浏览器上的键值对,安全性较差,保存的串一般为服务端识别客户端设置的唯一值(相当于id,<4KB)
session:保存在服务端上的键值对,和客服端访问时携带的串相匹配,识别不同用户取出对应私密信息(可以大于4KB)
django 操作 Cookie
服务端产生随机的串儿返回给客户端,服务端将信息存起来('随机字符串':'信息')
将以下👇路径设置关掉,网站将失去登录、保存状态的功能
Google浏览器>设置>高级>隐私设置和安全性>网站设置>权限>Cookie>允许网站保存和读取Cookie数据
django视图层函数return的HttpResponse、render、redirect终归为HttpResponse对象:
设置cookie
obj = HttpResponse() return obj obj = render() return obj obj = redirect() return obj # 给浏览器设置cookie,将于此时操作: obj.set_cookie('键','值',expires=超时登录秒) return obj # 注意:max_age设置超时登录,IE不能识别,多用expires
获取cookie
request.COOKIES.get('name') request.COOKIES['name']
删除cookie
obj.delete_cookie('值')
应用实例:
1. 没有登录不能访问其他页面,访问时直接跳转到登录页面
2. 装饰器内通过target_path = request.get_full_path()获取用户想访问的路径,给login路径添加get参数login/?next='%s' % target_path
3. login视图函数通过request.GET.get('next')获取用户想访问的路径
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^home/', views.home), url(r'^reg/', views.reg), url(r'^login/', views.login), url(r'^index/', views.index), url(r'^logout/', views.logout), ]
视图层views
from django.shortcuts import render, HttpResponse, redirect def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'jason' and password == '123': old_path = request.GET.get('next') # 获取原登录目标 if old_path: obj = redirect(old_path) # 登录成功,跳转原目标网页 else: obj = redirect('/home/') # 直接开登录界面,设置home为跳转页面 # 登录成功,给浏览器设置一个cookie obj.set_cookie('name', 'jason', expires=3600*24*7) # 设置超时登录时间,单位为秒 return obj return render(request, 'login.html') def index0(request): if request.COOKIES.get('name'): return HttpResponse('index,登陆可见!!') return redirect('/login/') from functools import wraps def login_auth(func): @wraps(func) # 装饰器修复 def inner(request, *args, **kwargs): old_path = request.get_full_path() # 获取验证登录前访问地址 if request.COOKIES.get('name'): # 校验cookie return func(request, *args, **kwargs) return redirect("/login/?next=%s" % old_path) # 携带访问目标地址 return inner @login_auth def index(request): return HttpResponse('index,登陆可见!!') @login_auth def home(request): return HttpResponse('home页面,登录可见!!') @login_auth def reg(request): return HttpResponse('reg页面,登录可见!!') # 删除cookie def logout(request): rep = redirect('/login/') rep.delete_cookie('name') # 删除用户浏览器上设置的usercookie值 return rep
django 操作 Session
关于session:
django 默认的session存活时间14天 *******
一个浏览器固定占一行session信息,代码中设置多行将会加密到一行中,不影响取值
设置session将会执行三件事:
1. 生成一个随机字符串
2. django表中存储该随机字符串与数据记录:执行后在内存中产生临时缓存,经过SessionMiddleware保存到数据库中
3. 将随机字符串发送给客户端浏览器,浏览器生成一个sessionid键存放session值
取出session时,经过以下步骤:
1. django自动获取浏览器随机字符串,去django session表比对
2. 比对成功,将随机对应的字符串对应的数据,赋值给request.session
3. 通过request.session操作该数据(不存在也不会影响其他代码)
request.session['name'] = 'jason' # 设置
request.session.get('name') #获取
request.session.delete() # 删除当前会话所有Session(数据库)
request.session.flush() # 删除当前会话数据及Cookie(数据库、浏览器)
# 获取、设置、删除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的超时时间:
如果value是个整数,session会在些秒数后失效。
如果value是个datatime或timedelta,session就会在这个时间后失效。
如果value是0,用户关闭浏览器session就会失效。
如果value是None,session会依赖全局session失效策略。
request.session.set_expiry(value)
应用实例
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^set_session/', views.set_session), url(r'^get_session/', views.get_session), url(r'^delete_session/', views.delete_session), url(r'^flush_session/', views.flush_session), ]
def set_session(request): request.session['name'] = 'jason' request.session['name1'] = 'egon' request.session['name2'] = 'tank' request.session['name3'] = 'nick' request.session['name4'] = 'sean' return HttpResponse('ok') def get_session(request): print(request.session.get('name')) print(request.session.get('name1')) print(request.session.get('name2')) print(request.session.get('name3')) print(request.session.get('name4')) return HttpResponse('ok') def delete_session(request): request.session.delete() return HttpResponse('ok') def flush_session(request): request.session.flush() return HttpResponse('ok')
设置session时,数据库中的表不存在,将会报错