Django之Form详解
Django的Form主要具有一下几大功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
1、创建Form类、View函数处理
from django import forms
from django.forms import widgets # widgets插件相关功能,包括了HTMl中INPUT、select、checkbox、radio等等全部标签
from django.forms import fields # fields:字段相关功能 class FM(forms.Form):
"""
下面的所有字段名字必须和前端的变量name的值相同,否则拿不到值
字段本身只用作验证的功能,fields负责生成HTML
"""
user = fields.CharField(
error_messages={'required': '用户名不能为空.'},
widget=widgets.Textarea(attrs={'class': 'c1'}), # widget设置表单字段在html页面的类型,attrs给表单标签设置属性
label='用户名',
initial='root',
help_text='请输入用户名(手机号、邮箱)'
) pwd = fields.CharField(
max_length=12,
min_length=6,
error_messages={'required': '密码不能为空', 'min_length': '密码长度不能小于6', 'max_length': '密码长度不能大于12'},
widget=widgets.PasswordInput(attrs={'class': 'c2'}),
label='密码',
)
email = fields.EmailField(error_messages={'required': '邮箱不能为空.', 'invalid': '邮箱格式错误'}) # 自定义错误信息 f = fields.FileField() city = fields.ChoiceField(
choices=[(0, '上海'), (1, '北京'), (2, '东莞')] # 每个元组中的第0个元素是前端select标签中的option标签的value属性
)
city1 = fields.MultipleChoiceField(
choices=[(0, '上海'), (1, '北京'), (2, '东莞')]
) def fm(request):
if request.method == "GET":
'''
打开一个新的编辑页面把默认值都获取到:创建个字典,把类中的字段一一写为字典的key,字典的值即为默认值,可以通过models从数据库获取
传递对象到前端时加上initial=dic参数即可设置默认值
注意:字段名必须和自定义类中的字段一一对应
'''
dic = {
'user': 'r1',
'pwd': '',
'email': 'asd@asd',
'city1': 1,
'city2': [1, 2],
}
obj = FM(initial=dic)
return render(request, 'fm.html', {'obj': obj}) # 打开页面,并将表单验证类对象传到html生成表单标签,利用表单类自动创建表单标签
elif request.method == "POST":
obj = FM(request.POST) # 创建验证表单类,将用户请求POST对象传进Form类中进行表单验证
r1 = obj.is_valid() # is_valid方法:对form中每一个字段逐一进行验证,返回验证是否通过的布尔值
if r1:
print(obj.cleaned_data) # 以字典的形式返回正确信息
models.UserInf.objects.create(**obj.cleaned_data) # 利用cleaned_data实现注册
else:
# print(obj.errors.as_json())
# print(obj.errors['user']) # errors方法包含了所有的错误信息,取值通过字典方式
print(obj.errors)
return render(request, 'fm.html', {'obj': obj})
2、生成HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app03/fm/" method="POST">
{% csrf_token %}
<p>{{ obj.user.label }} {{ obj.user }} {{ obj.errors.user.0 }} {{ obj.user.help_text }}</p>
<p>{{ obj.pwd.label }} {{ obj.pwd }} {{ obj.errors.pwd.0 }}</p>
<p>{{ obj.email }} {{ obj.errors.email.0 }}</p>
<p><input type="submit" value="提交"></p> {# <p>{{ obj.f }} {{ obj.errors.f.0 }}</p>#} <p>{{ obj.city }}</p>
<p>{{ obj.city1 }}</p>
</form>
</body>
</html>
widget插件设置表单字段在html页面的类型,包括了HTMl中INPUT、select、checkbox、radio等等全部标签 使用方式:widget=widgets.Textarea() 或widget=forms.Textarea(),推荐第一种写法
Textarea(): <textarea>标签类型
TextInput():<input>标签类型 attrs给表单标签设置属性,可以给标签元素设置class样式,和input标签的各种type属性
pwd = forms.CharField(
widget=forms.TextInput(attrs={'type':'password','class':'c1'}),
) 其他方法:
EmailInput、URLInput、PasswordInput等等,如需定制样式直接在后面加对应的属性attrs参数即可
widget=widgets.PasswordInput(attrs={'class': 'c2'})
扩展
需要实例化手动写的form模块的FORM类 ,要将所有request的post数据传入比如 f1 = form.Form(request.POST) 这样前端的html的所有提交的input就会验证 返回两种数据
1 cleaned_data 提交的正确数据(字典)
2 errors 错误信息 cleaned_data获取验证通过后的所有提交数据,返回字典
使用方式:obj.cleaned_data errors获取验证错误信息,返回所有表单的错误信息对象
使用方法:obj.errors 格式:
cleaned_data:以字典的形式返回(form验证通过)正确信息
{'user': 'asdasd', 'email': 'wuyuan@123.com', 'pwd': ''}
models.UserInf.objects.create(**obj.cleaned_data) # 利用cleaned_data实现注册 errors errors.as_json():
{"email": [{"code": "required", "message": "This field is required."}],
"user": [{"code": "required", "message": "This field is required."}],
"pwd": [{"code": "required", "message": "This field is required."}]} # 自定义错误信息时,根据code的值来定义,如:
error_messages={'required': '邮箱不能为空.', 'invalid': '邮箱格式错误'}
error_messages={'required': '密码不能为空', 'min_length': '密码长度不能小于6', 'max_length': '密码长度不能大于12'} 错误信息返回到前端:
<p>{{ obj.user }} {{ obj.errors.user.0 }}</p> # obj.user自动生成input标签,obj.errors.user.0 ,错误信息message的值
<p>{{ obj.user }} {{ obj.errors.user.0 }}</p>
<p>{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p>
<p>{{ obj.email }} {{ obj.errors.email.0 }}</p> 利用表单类自动创建表单标签 1、首先在get访问页面时,创建表单类不传参数,然后把这个表单类传到html页面,在html页面通过,表单类.字段名称,来自动创建表单标签 每一种表单字段类型,都有一个默认的表单标签,这个标签是可以更改的,所以表单类可以创建任何表单标签
<p>{{ obj.user }} {{ obj.errors.user.0 }}</p>
<p>{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p>
<p>{{ obj.email }} {{ obj.errors.email.0 }}</p>
2、在post访问时,再次创建表单类需要传参,将post请求对象传入表单类进行验证表单,如果表单不合法,将错误信息对象传到html显示错误信息,将这次创建的表单类传到html页面替换get时创建的表单类 小结:
1、通过form可以做用户请求的验证
2、帮前端在页面生成HTML标签,且同时会保留上一次提交的内容在输入框中
注意:生成HTML的功能在新URL方式(form提交)时使用,
而对于ajax请求方式(不会刷新,不会跳转URL)不用生成HTML的功能
小结
Form类
创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;
1、Django内置字段:
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[], 自定义验证规则、正则表达式
'''
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
'''
localize=False, 是否支持本地化,jango默认使用UTC时间,加上这个参数则在页面时间加上8小时变为本地时间
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) # 功能相当于CharField 结合 validators
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} EmailField(CharField)
... FileField(Field)
allow_empty_file=False 是否允许空文件 '''
f = fields.FileField()
<p>{{ obj.f }} {{ obj.errors.f.0 }}</p>
在前端上传文件后,以字典形式保存在cleaned_data中{'f': '文件对象'}
'''
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='', 帮助提示 MultipleChoiceField(ChoiceField) # 生成可以多选的下拉框
... 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= '' 空值的默认值 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类型
常用选择插件:
# 单radio: # 单radio,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
) # 单radio,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.RadioSelect
) # 单select实现方式: # 方式一:利用widgets.Select方法 单select,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
) # 方式二:利用fields.ChoiceField方法,单select,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
# widget=widgets.Select
) 使用示例:
class UserInfoForm(forms.Form):
user_type = fields.ChoiceField(
# choices=[(1, '普通用户'), (2, '超级用户')],
choices=models.UserType.objects.values_list('id', 'name'),
) user_type2 = fields.CharField(
# widget=widgets.Select(choices=[(0, '上海'), (1, '北京'), (2, '东莞')])
widget=widgets.Select(choices=models.UserType.objects.values_list('id', 'name'))
) # 多选select,利用fields.MultipleChoiceField方法,值为列表
user = fields.MultipleChoiceField(
choices=((1,'上海'),(2,'北京'),),
initial=[1,],
widget=widgets.SelectMultiple
) # 多选select,利用fields.CharField方法,值为列表
user = fields.CharField(
choices=((1,'上海'),(2,'北京'),),
initial=[1,],
widget=widgets.SelectMultiple(choices=((1,'上海'),(2,'北京'),))
) 使用示例:
class UserInfoForm(forms.Form):
user_type3 = fields.MultipleChoiceField(
# choices=[(1, '普通用户'), (2, '超级用户')],
choices=models.UserType.objects.values_list('id', 'name'),
) user_type4 = fields.CharField(
# widget=widgets.SelectMultiple(choices=[(0, '上海'), (1, '北京'), (2, '东莞')])
widget=widgets.SelectMultiple(choices=models.UserType.objects.values_list('id', 'name'))
) # 单checkbox
user = fields.CharField(
widget=widgets.CheckboxInput()
) # 多选checkbox,值为列表
user = fields.MultipleChoiceField(
initial=[2, ],
choices=((1, '上海'), (2, '北京'),),
widget=widgets.CheckboxSelectMultiple
)
2、Django内置插件:
Django,Form内置插件:
# 每个插件里面都可以加上attrs={} 来自定义属性 TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
动态select的两种实现方式:
方式一(推荐,不用改models):
通过重写父类构造方法,构造方法只有在创建类的实例的时候才会执行,利用构造方法的特性,实例化为对象时去数据库select可实现动态select获取,之后封装到对象中返回前端即可
from django import forms
from django.forms import fields
from django.forms import widgets
from app03 import models class UserInfoForm(forms.Form):
user = fields.CharField(
required=False,
widget=widgets.Textarea(attrs={'class': 'c1'})
) pwd = fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={'class': 'c1'})
)
# 针对两种select框创建方式分别实现动态select
user_type = fields.ChoiceField(
# choices=models.UserType.objects.values_list('id', 'name'), # 构造方法中定义choices后,这里取的值没用了
choices=[]
) user_type2 = fields.CharField(
widget=widgets.Select(choices=[])
) def __init__(self, *args, **kwargs):
"""
重写父类构造方法,构造方法只有在创建类的实例的时候才会执行,
利用构造方法的特性,实例化为对象时去数据库select可实现动态select获取,之后封装到对象中
"""
super(UserInfoForm, self).__init__(*args, **kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id', 'name') # 每次实例化为对象时都会去数据库中取数据
self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id', 'name') # 针对两种select框创建方式分别实现动态select
form.py
from app03.forms import UserInfoForm def form(request):
if request.method == "GET":
obj = UserInfoForm()
return render(request, 'index.html', {'obj': obj})
views.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
{% csrf_token %}
<p>{{ obj.user_type }}</p>
<p>{{ obj.user_type2 }}</p>
</body>
</html>
index.html
方式二:
通过jango的ModelChoiceField类实现:
forms.py:
from django.forms.models import ModelChoiceField,ModelMultipleChoiceField # ModelMultipleChoiceField 多选,用法同单选 class UserInfoForm(forms.Form): user_type3 = ModelChoiceField(
queryset=models.UserType.objects.all(),
empty_label='请选择用户类型',
to_field_name='id' # HTML中select标签下option标签的value的值对应的字段
) models.py: class UserType(models.Model):
name = models.CharField(max_length=32) def __str__(self): # 必须在models中定义str方法
return self.name 前端页面同方式一
Django Form之钩子函数:
为了对Form正则验证后的数据进行进一步的验证:如注册验证(用户是否存在)、登录验证(用户名密码是否正确),使用钩子函数可以完成此类验证
源码分析:
通过验证的is_valid方法的源码,找到full_clean方法如下:
def full_clean(self):
"""
Clean all of self.data and populate self._errors and self.cleaned_data.
"""
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed():
return self._clean_fields() # 钩子函数,分别对指定的每一个字段进行验证
self._clean_form() # 查看_clean_form源码,可知调用了全局钩子函数clean()
self._post_clean() 看_clean_fields私有字段可知:
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value # 当完成了钩子函数之前的验证后,验证通过的数据会暂时的存放在form.cleaned_data中
if hasattr(self, 'clean_%s' % name): # 如果有钩子函数
value = getattr(self, 'clean_%s' % name)() # 执行钩子函数
self.cleaned_data[name] = value # 钩子函数验证后的返回值存入cleaned_data
except ValidationError as e: # 验证失败add_error
self.add_error(name, e) def _clean_form(self):
try:
cleaned_data = self.clean() # 全局钩子函数
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data 注意:
1、只能拿自己当前字段值,钩子函数体内应该使用与其函数名匹配的字段
2、钩子函数必须要有返回值
3、遍历验证字段的时候,前一个字段验证过后,后一个字段的局部钩子函数中也不一定能够用clean_data获取到前一个字段的值,因为前一个字段的值如果验证不通过是不会存放在clean_data中
示例:
注册验证:
form.py:
class RegisterForm(forms.Form): user = fields.CharField(
error_messages={'xxx': '用户名已存在'},
min_length=2,
required=False,
label='用户名:',
widget=widgets.TextInput(attrs={'class': 'c1'})
)
pwd = fields.CharField(
max_length=12,
label='密码:',
widget=widgets.PasswordInput(attrs={'class': 'c1'})
) email = fields.EmailField(validators=[]) def clean_user(self):
"""
正则验证通过后,验证用户是否存在,注册验证
:return: 通过后把数据放到cleaned_data中返回
"""
c = models.User.objects.filter(user=self.cleaned_data.get('user')).count()
print(self.fields.items(), '-----------------------', self.cleaned_data['user'])
print(self.cleaned_data['user'])
if not c:
return self.cleaned_data['user']
else:
raise ValidationError('用户名已存在!', code='xxx') views.py:
def register(request):
if request.method == "GET":
obj = RegisterForm()
return render(request, 'index.html', {'obj': obj})
elif request.method == "POST":
obj = RegisterForm(request.POST, initial={'user': request.POST.get('user')}) # 提交验证失败保留用户名
obj.is_valid()
print(obj.errors)
return render(request, 'index.html', {'obj': obj}) models.py class User(models.Model): user = models.CharField(max_length=32)
pwd = models.CharField(max_length=64) index.html:
<form action="/app03/register/" method="post">
{% csrf_token %}
<p>{{ obj.user.label }}{{ obj.user }}</p>
<p>{{ obj.pwd.label }}{{ obj.pwd }}</p>
{# <p>{{ obj.user_type3 }}</p>#}
<p><input type="submit" value="提交"></p>
</form>
登录验证:
from django import forms
from django.forms import fields
from django.forms import widgets
from app03 import models
from django.forms.models import ModelChoiceField,ModelMultipleChoiceField
from django.core.exceptions import ValidationError class RegisterForm(forms.Form): user = fields.CharField(
error_messages={'xxx': '用户名已存在'},
min_length=2,
required=False,
label='用户名:',
widget=widgets.TextInput(attrs={'class': 'c1'})
)
pwd = fields.CharField(
max_length=12,
label='密码:',
widget=widgets.PasswordInput(attrs={'class': 'c1'})
) def clean(self):
"""
全局钩子函数clean,能拿到cleaned_data中所有验证通过的数据,对整体进行验证,可以进一步进行登录验证
:return:
"""
# c = models.User.objects.filter(user=self.cleaned_data['user'], pwd=self.cleaned_data['pwd']).count()
# a = {'user': self.cleaned_data.get('user'), 'pwd': self.cleaned_data.get('pwd')}
print(self.cleaned_data,'cleaned_data -----2222222222222222222222222')
c = models.User.objects.filter(user=self.cleaned_data.get('user'), pwd=self.cleaned_data.get('pwd')).count()
print(c, 'this is c---------')
if c:
return self.cleaned_data
else:
raise ValidationError('用户名或密码错误', code='xxx') views.py: from app03.forms import RegisterForm def register(request):
if request.method == "GET":
obj = RegisterForm()
return render(request, 'index.html', {'obj': obj})
elif request.method == "POST":
obj = RegisterForm(request.POST, initial={'user': request.POST.get('user')}) # 提交验证失败保留用户名
obj.is_valid()
print(obj.errors)
return render(request, 'index.html', {'obj': obj})
from django.core.exceptions import NON_FIELD_ERRORS
'''
{
'__all__':[], # 整体验证clean方法的错误信息放在这里 , 也可以写成NON_FIELD_ERRORS(点击看源码可知代指字符串__all__)
"email": [{"code": "required", "message": "This field is required."}],
"user": [{"code": "required", "message": "This field is required."}],
"pwd": [{"code": "required", "message": "This field is required."}]
}
'''
clean方法的错误信息
小结:
form 验证流程:
1、前端提交数据到后台form
2、循环判断所有字段根据正则表达式(默认或自定义正则)
3、执行字段对应的钩子函数,再判断下一个字段(正则、钩子函数)
4、所有字段循环完毕,最后执行clean钩子函数、post钩子 客户端POST提交的数据作为我们自定义Form类的参数实例化的得到的form对象可以帮助我们进行表单验证,他验证的流程大致是这样的
循环遍历用户提交的POST表单中的数据,取出存在于自定义的Form类中的字段,比如name,password。
将取出的字段按照自定义的Form类中字段的验证规则(包括是否为空、长短、以及正则等)进行验证
如果Form类中定义了钩子函数cleaned_字段名,就会调用钩子函数,对指定的字段进行更精细的验证(比如用户登陆)
自定义验证规则
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
方式一
import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError # 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class PublishForm(Form): title = fields.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': '标题5-20个字符'})) # 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'})) email = fields.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
方式二:自定义函数
from django import forms
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator class FInfo(forms.Form):
username = fields.CharField(max_length=5,
validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
email = fields.EmailField() def clean_username(self):
"""
Form中字段中定义的格式匹配完之后,执行此方法进行验证
:return:
"""
value = self.cleaned_data['username']
if "" in value:
raise ValidationError('666已经被玩烂了...', 'invalid')
return value
方法三:自定义方法(钩子函数)
from django.forms import Form
from django.forms import widgets
from django.forms import fields from django.core.validators import RegexValidator ############## 自定义字段 ##############
class PhoneField(fields.MultiValueField):
def __init__(self, *args, **kwargs):
# Define one message for all fields.
error_messages = {
'incomplete': 'Enter a country calling code and a phone number.',
}
# Or define a different message for each field.
f = (
fields.CharField(
error_messages={'incomplete': 'Enter a country calling code.'},
validators=[
RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
],
),
fields.CharField(
error_messages={'incomplete': 'Enter a phone number.'},
validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
),
fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
required=False,
),
)
super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
**kwargs) def compress(self, data_list):
"""
当用户验证都通过后,该值返回给用户
:param data_list:
:return:
"""
return data_list ############## 自定义插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
def __init__(self):
ws = (
widgets.TextInput(),
widgets.TextInput(),
widgets.TextInput(),
)
super(SplitPhoneWidget, self).__init__(ws) def decompress(self, value):
"""
处理初始值,当初始值initial不是列表时,调用该方法
:param value:
:return:
"""
if value:
return value.split(',')
return [None, None, None]
方式四:同时生成多个标签进行验证
初始化数据:
在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。
# Form:
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator class MyForm(Form):
user = fields.CharField() city = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
widget=widgets.Select
) # Views:
from django.shortcuts import render, redirect
from .forms import MyForm def index(request):
if request.method == "GET":
values = {'user': 'root', 'city': 2}
obj = MyForm(values) return render(request, 'index.html', {'form': obj})
elif request.method == "POST":
return redirect('http://www.google.com')
else:
return redirect('http://www.google.com') # HTML <form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.user }} {{ form.user.errors }}</p>
<p>{{ form.city }} {{ form.city.errors }}</p> <input type="submit"/>
</form>
Django之Form详解的更多相关文章
- Django入门基础详解
本次使用django版本2.1.2 安装django 安装最新版本 pip install django 安装指定版本 pip install django==1.10.1 查看本机django版本 ...
- 第五篇Django URL name 详解
Django URL name 详解 利用Django开发网站,可以设计出非常优美的url规则,如果url的匹配规则(包含正则表达式)组织得比较好,view的结构就会比较清晰,比较容易维护. Djan ...
- Django之model详解
Django中的页面管理后台 Djano中自带admin后台管理模块,可以通过web页面去管理,有点想php-admin,使用步骤: 在项目中models.py 中创建数据库表 class useri ...
- Django models Fild详解
本文参考自:django官方文档models/field 在model中添加字段的格式一般为: field_name = field_type(**field_options) 一 field o ...
- Django model 字段详解
字段类型选择: AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 ...
- django session入门详解
概括性的讲: 1.django默认是打开对session的支持的 2.默认情况下session相关的数据会保存在数据库中.浏览器端只保存了session id session 的科普: 1.动态网站中 ...
- Django之ModelForm详解
前言 这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来.先来一个简单的例子来看一下这个东西怎么用: 比如我们的数据库中有这样一张学生表,字段有姓名,年龄,爱 ...
- django rest framework 详解
Django REST framework 是用于构建Web API 的强大而灵活的工具包. 我们可能想使用REST框架的一些原因: Web浏览API对于开发人员来说是一个巨大的可用性. 认证策略包括 ...
- Django之session详解
好文章来自追风的小蚂蚁:https://www.cnblogs.com/zhuifeng-mayi/p/9099811.html cookie:Cookie,有时也用其复数形式 Cookies,指某些 ...
随机推荐
- jira报错,此域不支持您输入的日期
jira报错,此域不支持您输入的日期 解决方法: 使用20117-1-1这样的格式输入,不要用选择日期.具体原因未知.
- 工作总结 错误 using 块缺少结束字符“}”。请确保此块内的所有“{”都有匹配的“}”字符,并且任何“}”都不会解释为标记。
页面上 有两个 它会跟标签 匹配的 标准要在同一级别下 什么也不改变 只改变它们位置 就不报错了 总结 @using (Html.BeginForm()) { } 要根据标签位置 匹配 要放 ...
- docker教程之从一头雾水到不一头雾水(1)
一.安装docker 1.搜索docker [root@node3 ~]# yum search docker Loaded plugins: fastestmirror, langpacks Loa ...
- Exploiting CVE-2015-2509 /MS15-100 : Windows Media Center could allow remote code execution
Exploiting CVE-2015-2509 /MS15-100 : Windows Media Center could allow remote code execution Trend Mi ...
- Java并发编程(一)学习大纲
(一)学习大纲 (二)线程与并发编程的概念 (三)线程安全.原子操作.复合操作.竞态条件.加锁机制(内置锁.重入) (四)对象的共享:可见性.失效数据.非原子的64位操作,加锁与可见性,volatil ...
- sublime使用技巧(4)-- 其他技巧【持续更新】
命令模式 1.切换语言格式,ctrl + shirt + p 2.简化操作 ctrl + shirt + p 输入 snippet:function 自动生成function的基本结构!tab键 移动 ...
- strpos 判断字符串是否存在
strpos 中为什么要用逗号隔开的原因是因为 防止找出相匹配的中 , 如 查找1 而数组中 存在 12 那么这个结果也是可以找出来的 ,分别在1 前后加个, 就是为了区 ...
- openresty 定时器
[1]nginx定时器应用 (1)文件目录结构 (2)nginx.conf配置 lua_package_path "/usr/local/lib/ubcsrvd/lualib/?.lua;; ...
- winphone 中的指针和手势事件
注意 有关这些主题的最新概述,请参阅指针事件和手势事件主题. 小心 W3C 指针事件规范自从在 Internet Explorer 10 中实施以来,已经经历了多次修订.此外,截止到 Intern ...
- Spring JDBC查询返回对象代码跟踪
在封装方法的时候突然发现通过 ResultSetMetaData的getColumnCount()获取到的列明会多一列(ROWSTAT),而且每次的值都是1,目前没有找到相关信息,在国外网站上看到有类 ...