前言
Form组件的几大作用
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML 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) #验证失败返回<ul class="errorlist"><li>user<ul class="errorlist"> # <li>Ensure this value has at least 6 characters (it has 4).</li></ul></li></ul> return redirect('http://www.baidu.com') else: #显示错误信息 print('验证失败',obj.errors) #验证成功返回字典 {'user': '121212', 'pwd': '11111111111111111111111111111111', 'age': 12, 'email': '11111111@qq.com'} return render(request,'f1.html',{'obj':obj}) return HttpResponse('OK')
html
<form id="fm" action="/f1.html" method="POST" novalidate> <!-- <P><input type="text" name="user"/>{{ obj.errors.user.0 }}</P> <P><input type="text" name="pwd"/>{{ obj.errors.pwd.0 }}</P> <P><input type="text" name="age"/>{{ obj.errors.age.0 }}</P> <P><input type="text" name="email"/>{{ obj.errors.email.0}}</P> --> <!-- <p>{{ obj.as_p }}</p> --> <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)