Forms组件
需求
如果需要编写一个校验用户名和密码是否合法的功能,那么
- 前端需要自己编写获取用户数据的各种标签
- 前端需要自己想方设法的展示错误的提示信息
- 后端需要自己想方设法的编写校验代码(很多if判断)
form组件
上面的三件事有一个人可以一次性帮你搞定:form组件
- 数据校验
- 标签渲染
- 展示信息
基本使用
在views.py里面编写校验性组件forms类
from django import forms
class MyForm(forms.Form):
# 用户名至少三个字符最多八个字符
username = forms.CharField(min_length=3,max_length=8)
# 年龄最小不能小于0 最大不能超过150
age = forms.IntegerField(min_value=0,max_value=150)
# 邮箱必须符合邮箱格式(@关键符号)
email = forms.EmailField()
校验数据
校验
可以在pycharm的测试环境Python console测试一下
from app01 import views
1.将数据传入实例化对象
form_obj =MyForm({'username':'jason','age':18,'email':'123qq'})
2.查看数据是否合法(全部合法结果才是True)
form_obj.is_valid()
3.查看不符合条件的数据及原因
form_obj.errors
{'email': ['Enter a valid email address.']}
4.查看符合条件的数据
form_obj.cleaned_data
{'username': 'jason', 'age': 18}
注意事项
forms类中所有的字段数据默认都是必填的,不能少,如果想忽略某些字段,可以添加 required=False
forms类中额外传入的字段数据不会做任何的校验,直接忽略
渲染标签
渲染方式1
{{ form_obj.as_p }}
{{ form_obj.as_table }}
{{ form_obj.as_ul }}
封装程度高 扩展性较差 主要用于快速生成页面测试功能
渲染方式2
{{ form_obj.username.label }} # 文本提示
{{ form_obj.username }} # 获取用户数据的标签
封装程度低 扩展性较好 但是字段比较多的情况下不方便
渲染方式3
{% for form in form_obj %}
{{ form.label }}
{{ form }}
{% endfor %}
推荐使用
forms组件只负责渲染获取用户数据的标签, form表单标签和提交按钮需要自己写
渲染标签中文提示,可以使用 参数label指定,不指定默认使用字段名首字母大写
展示信息
添加校验操作
forms类中填写的校验性参数前端浏览器会识别并添加校验操作
但是前端的校验是可有可无的,不能指望它,后端必须要有
补充
form表单可以 取消浏览器自动添加校验功能的操作
自定义提示信息
username = forms.CharField(min_length=3,max_length=8,label='用户名',error_messages={
'min_length':'用户名最短3位',
'max_length':'用户名最长8位',
'required':'用户名必填'
})
钩子函数
含义
在程序的执行过程中穿插额外的逻辑,钩子函数是数据经过了字段第一层参数校验之后才会执行
局部钩子
校验单个字段,以校验用户名是否已存在(一次性只能勾一个)
def clean_name(self): # 自动生成的函数名 专门用于对name字段添加额外的校验规则
# 1.先获取用户名
name = self.cleaned_data.get('name')
# 2.判断用户名是否已存在
is_exist = models.User.objects.filter(name=name)
if is_exist:
# 3.提示信息
self.add_error('name', '用户名已存在')
# 4.最后将你勾上来的name返回回去
return name
View Code
全局钩子
校验多个字段,校验密码和确认密码是否一样
def clean(self):
# 1.获取多个字段数据
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
View Code
字段参数
initial
初始值,input框里面的初始值
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三" # 设置默认值
)
pwd = forms.CharField(min_length=6, label="密码")
View Code
validators
正则校验器
from django.core.validators import RegexValidator
phone = forms.CharField(
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
View Code
widget
控制渲染出来的标签各项属性
forms.widgets.控制type的类型(attrs=控制各项属性:class id …) 执行到PasswordInput已经是密文展示了
name = forms.CharField(min_length=3, max_length=8, initial='XXX',
label='用户名', error_messages={
'min_length': '用户名最少三位',
'max_length': '用户名最多八位',
'required': '用户名不能为空'
}, widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(min_length=3, max_length=8, label='密码', widget=forms.widgets.PasswordInput({'class': 'form-control'}))
View Code
radioSelect
单radio值为字符串
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
View Code
单选Select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
View Code
多选Select
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
View Code
单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
View Code
多选checkbox
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
View Code
choices
选择类型的标签内部对应关系,可以直接编写,也可以从数据库中获取
比较两者的不同
user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
def __init__(self, *args, **kwargs):
super(MyForm,self).__init__(*args, **kwargs)
# self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')
View Code
from django import forms
from django.forms import fields
from django.forms import models as form_model
class FInfo(forms.Form):
authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多选
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 单选
View Code
字段类型
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
BaseTemporalField(Field)
input_formats=None 时间格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 时间间隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否允许空文件
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值
ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) uuid类型
View Code
源码分析
def is_valid(self):
return self.is_bound and not self.errors
查看类源码发现只要给类传参self.is_bound肯定是True
@property
def errors(self):
if self._errors is None:
self.full_clean()
return self._errors
查看了源码发现self._errors初始化就是None 所以肯定走full_clean方法
查看源码发现校验数据的整个过程内部都有异常处理机制
from django.core.exceptions import ValidationError
raise ValidationError('用户名不存在 你个DSB')
只对局部钩子有效
ModelForm
通常在Django项目中,我们编写的大部分都是与Django 的模型紧密映射的表单。 举个例子,你也许会有个Book 模型,并且你还想创建一个form表单用来添加和编辑书籍信息到这个模型中。在这种情况下,在form表单中定义字段将是冗余的,因为我们已经在模型中定义了那些字段。
基于这个原因,Django 提供一个辅助类来让我们可以从Django 的模型创建Form,这就是ModelForm
class MyUser(forms.ModelForm):
class Meta:
model = models.User # 指定关联的表
fields = '__all__' # 所有的字段全部生成对应的forms字段
labels = {
'name': '用户名',
'age': '年龄',
'addr': '地址',
'email': '邮箱'
}
widgets = {
"name": forms.widgets.TextInput(attrs={"class": "form-control"}),
}
def reg(request):
form_obj = MyUser()
if request.method == 'POST':
form_obj = MyUser(request.POST)
if form_obj.is_valid():
# form_obj.save() # 新增数据
edit_obj = models.User.objects.filter(pk=5).first()
form_obj = MyUser(request.POST, instance=edit_obj) # 是新增还是保存就取决于有没有instance参数
form_obj.save() # 编辑数据
return render(request, 'reg.html', locals())
View Code
cookie与session
概念
早期的互联网应用程序都是不保存用户状态的,所有人发送请求返回的都是相同的页面,现如今几乎所有的应用程序都可以保存用户状态
HTTP协议四大特性之一:无状态
让服务端知道你是谁的方式很单一>>>:携带用户名和密码(身份标识)
每次操作之前都需要输入用户名和密码,当你成功登录之后浏览器会在本地帮你保存用户名和密码,每次操作浏览器自动发送用户名和密码
本质
指代服务端让客户端保存的数据:存储在客户端上与用户信息相关的数据;cookie就是存在客户端的东西
视图函数返回值
不直接返回视图函数的对象,而是先用变量名指代,然后操作对象方法
基本使用
res.set_cookie():设置
res.COOKIE.get():获取
装饰器
有很多视图函数需要添加登录认证,有时候又需要取消登录认证
补充
加密盐
set_signed_cookie(key,value,salt='加密盐')
超时时间
set_signed_cookie(key,value,max_age=超时时间:默认是秒数)
注销登录
HttpResponse对象.delete_cookie(key)
登录操作的本质:核心就是cookie的存取
session
概念
早期的cookie是直接存储的用户明文相关信息,不安全,用户登录成功之后,服务端生成一个随机字符串,返回给客户端保存,之后客户端每次发请求携带该随机字符串,服务端获取之后比对后台数据
本质
指代服务端保存的跟用户信息相关的数据,session就是存在服务端的东西
注意
session的工作必须依赖于cookie,客户端也有权拒绝保存数据
django操作session
服务端保存用户相关状态信息,返回给客户端随机字符串,针对保存,django需要一张表来处理
自带的django_session表
django数据库迁移命令会产生一堆默认的表,其中就有一张django_session表
设置
request.session['key'] = value # 可以设置多组
django默认的session失效时间是14天
设置session内部发生的事情
- 产生一个随机字符串
- 表中存储随机字符串与加密数据的对应关系
- 并将产生的随机字符串也给客户端发送一份并让其保存
获取
request.session.get('key') # 可以获取多组
获取session内部发生的事情
- 自动获取客户端请求中的随机字符串
- 自动去存储session数据的表中比对
- 如果比对成功自动获取并’解密处理’
补充
request.session.session_key # 获取产生的随机字符串
request.session.delete() # 只删客户端
request.session.flush() # 服务端 客户端都删
request.session.set_expiry(value) # 设置超时时间
- 如果value是个整数,session会在些秒数后失效
- 如果value是个datatime或timedelta,session就会在这个时间后失效
- 如果value是0,用户关闭浏览器session就会失效
- 如果value是None,session会依赖全局session失效策略
针对session数据的存储位置,有五种方案
- 数据库存储
- 缓存存储
- 文件存储
- 缓存+数据库存储
- 动态加密
Original: https://www.cnblogs.com/zzs0626/p/16303555.html
Author: 顺溜_7
Title: Forms组件;cookie与session
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582432/
转载文章受原作者版权保护。转载请注明原作者出处!