前言
Form组件的几大作用
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
目录
- Form组件的创建
- Form组件的内置字段
- Form组件的验证扩展
Form组件的创建
views
from django.shortcuts import render,HttpResponse,redirect from django import forms from django.forms import fields class F1Form(forms.Form): # 不能为空,长度6-18 user = fields.CharField( max_length=18, min_length=6, required=True, #自定义错误的提示 error_messages={ 'required': '用户名不能为空','max_length': '太长了','min_length': '太短了','invalid':'..'} ) # 不能为空,长度32 pwd = fields.CharField(required=True,min_length=32) # 不能为空,邮箱格式 age = fields.IntegerField( required=True, error_messages={ 'required':'年龄不能为空', 'invalid':'必须为数字'} ) # 不能为空,数字格式 email = fields.EmailField( required=True, min_length=8, error_messages={ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误'} ) def f1(request): if request.method == "GET": obj = F1Form() return render(request,'f1.html',{ 'obj':obj}) else: # u = request.POST.get('user') #不能为空,长度6-18 # p = request.POST.get('pwd') #不能为空,长度32 # e = request.POST.get('email') #不能为空,邮箱格式 # a = request.POST.get('age') #不能为空,数字格式 # print(u,p,e,a) # 检查是否为空 # 检查格式是否正确 obj = F1Form(request.POST) # 用户是否验证成功 if obj.is_valid(): #用户提交的数据 print('验证成功',obj.cleaned_data) #验证失败返回#
- user
Ensure this value has at least 6 characters (it has 4). return redirect('http://www.baidu.com') else: #显示错误信息 print('验证失败',obj.errors) #验证成功返回字典 {'user': '121212', 'pwd': '11111111111111111111111111111111', 'age': 12, 'email': '[email protected]'} return render(request,'f1.html',{ 'obj':obj}) return HttpResponse('OK')
html
<form id="fm" action="/f1.html" method="POST" novalidate> <p>{ { obj.as_p }}p> <P>{ { obj.user }}{ { obj.errors.user.0 }}P> <P>{ { obj.pwd }}{ { obj.errors.pwd.0 }}P> <P>{ { obj.age }}{ { obj.errors.age.0 }}P> <P>{ { obj.email }}{ { obj.errors.email.0}}P> <input type="submit" value="提交"/> form>
Form类的内置字段
Fields
required = True, #是否必填
error_messages = {} #自定义错误提示
widget = widgets.Select(), #定制HTML插件
label = '用户名', #{
{obj.user.label}}
initial = '请输入默认值', #添加默认值
help_text = '帮助文档',
show_hidden_initial = True, #是否在当前插件后面在加一个隐藏且具有默认值的插件(可用于检验两次输入是否一致)
validators = [], #自定制验证规则
localize = False, #是否支持本地化
disabled = False, #是否可编辑
label_suffix = ':', #后缀
CharField(Fields)
max_length = None, #最大长度
min_length = None, #最小长度
strip = True, #是否移除空白
error_messages = {'max_length': '太长了', 'min_length': '太短了'}, #自定义错误提示
RegexField(CharField)
regex, #自定制正则表达式
error_messages=None, #error_messages={'invalid':'格式错误的字段都是invalid'}
URLField(CharField)
...
EmailField(CharField)
...
SlugField(CharField) #数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) #uuid类型
...
FileField(Field)
max_length = None, #设置最大长度
allow_empty_file = False, #是否允许为空
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
ChoiceField(Field)
choices=(), #选项,如:choices = ((0,'上海'),(1,'北京'),)
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
FilePathField(ChoiceField) #文件选项,目录下文件显示在页面中
path, #文件夹路径
match=None, #正则匹配
recursive=False, #递归下面的文件夹
allow_files=True, #允许文件
allow_folders=False, #允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
IntegerField(Fields)
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 - 0111: 12
DurationField(Field) #时间间隔: % d % H: % M: % S. % f
...
GenericIPAddressField
protocol = 'both', #both, ipv4, ipv6支持的IP格式
unpack_ipv4 = False #解析ipv4地址,如果是::ffff: 192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
注:在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
方式一:
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
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'].widget.choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id', 'caption')
方法二:
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
from django import forms
from django.forms import fields
from django.forms import widgets
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())
Form组件的验证扩展
方法一:
使用RegexValidator模块
from django.forms import Form
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(
error_messages={'invalid': '.....'},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
方法二:
使用 RegexField字段
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid':'.....'})
方法三:
自定义方法,自定义方法 clean_字段名
from django.shortcuts import render
from django import forms
from django.forms import fields
from django.forms import widgets
from app03 import models
# Create your views here.
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class MyForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0, 'chen'), (1, 'xiaoyi'), (2, 'liu'), ])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']
#整体的错误信息返回
def clean(self):
value_dict = self.cleaned_data
v1 = value_dict.get('username')
v2 = value_dict.get('user_id')
if v1 == 'root' and v2 == 1:
raise ValidationError('整体错误信息')
return self.cleaned_data
在源码中会会通过反射去执行clean_"字段名"的方法,再将值赋值给self.cleaned_data[name]
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 if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value except ValidationError as e: self.add_error(name, e)