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类中额外传入的字段数据不会做任何的校验,直接忽略
{{ 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 %}
<p>
{{ form.label }}
{{ form }}
</p>
{% endfor %}
推荐使用
forms组件只负责渲染获取用户数据的标签,form表单标签和提交按钮需要自己写
渲染标签中文提示,可以使用参数label指定,不指定默认使用字段名首字母大写
添加校验操作
自定义提示信息
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 nameView 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_dataView 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')
只对局部钩子有效
基于这个原因,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
早期的互联网应用程序都是不保存用户状态的,所有人发送请求返回的都是相同的页面,现如今几乎所有的应用程序都可以保存用户状态
HTTP协议四大特性之一:无状态
让服务端知道你是谁的方式很单一>>>:携带用户名和密码(身份标识)
每次操作之前都需要输入用户名和密码,当你成功登录之后浏览器会在本地帮你保存用户名和密码,每次操作浏览器自动发送用户名和密码
本质指代服务端让客户端保存的数据:存储在客户端上与用户信息相关的数据;cookie就是存在客户端的东西
View Code 基本使用
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,客户端也有权拒绝保存数据
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数据的存储位置,有五种方案
- 数据库存储
- 缓存存储
- 文件存储
- 缓存+数据库存储
- 动态加密