
目录
Form组件介绍 常用字段与插件 Form组件中所有内置字段 从数据库中获取数据 校验示例 检验手机号是否合法 方式一(基本 *** 作) 方式二(自定义验证规则) 方式三(利用钩子) 验证密码一致性 钩子 局部钩子 全局钩子 进阶 批量添加样式 ModelForm Form套Form@
***
在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。
与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息。
Django form组件就实现了上面的功能。
先总结一下,form组件的主要功能如下:
生成页面可用的HTML标签 对用户提交的数据进行校验保留上传输入的内容
***
from django import forms# 按照Django form组件的要求自己写一个类# 且必须继承forms.Formclass RegForm(forms.Form): user = forms.CharFIEld(label="名称") pwd = forms.CharFIEld(label="密码",min_length=6)
视图文件:
from django.shortcuts import render,httpResponsefrom blog01 import forms # 导入上面的form文件def register(request): form_obj = forms.RegForm() if request.method == 'POST': form_obj = forms.RegForm(request.POST) if form_obj.is_valID(): # 只有执行了is_valID之后,才可执行cleaned_data,否则会报错 # cleaned_data的数据是经过校验的 print(form_obj.cleaned_data) return httpResponse("注册成功!") return render(request,'register.HTML',{'form': form_obj}) HTML文件:
<body>{# novalIDate:阻止验证(form组件会自动验证)#}<form action="" method="post" novalIDate>{% csrf_token %} {# {{ form.as_p }} 以p标签的形式自动生成 #} {# 下面为简单的自定义形式 #} <p> {{ form.user.label }} {{ form.user }} {# 错误提示信息 #} {# {{ form.errors }} 生成form表单的所有错误信息(全局错误信息)#} {# <span >{{ form.user.errors }}</span> 指定字段的所有错误信息 #} <span >{{ form.user.errors.0 }}</span> {# 指定字段的所有错误信息的第一个 #} </p> <p> {{ form.pwd.label }} {{ form.pwd }} <span >{{ form.pwd.errors.0 }}</span> </p> <button>注册</button></form></body> 常用字段与插件 from django import formsclass RegForm(forms.Form): user = forms.CharFIEld( label="名称",# 用于生成label标签或显示内容 # required=False,# 为False时,允许为空 min_length=2,# 最小长度 max_length=6,# 最大长度 initial='zyk01',# 初始值 error_messages={ 'required': "用户名不能为空",'invalID': "用户名格式错误",'min_length': "用户名最短2位",} # 自定义错误提示 ) pwd = forms.CharFIEld( label="密码",min_length=6,error_messages={ 'required': "密码不能为空",'invalID': "密码格式错误",'min_length': "密码最短6位",},Widget=forms.Widgets.Passwordinput(),# 指定input的type类型为password ) # =================================================== # # =================================================== """checkBox标签(单选)""" keep = forms.fIElds.CharFIEld( label="记住密码",initial='checked',# 默认选中 Widget=forms.Widgets.CheckBoxinput(),) """checkBox标签(多选)""" hobby01 = forms.fIElds.MultipleChoiceFIEld( label="爱好01",choices=((1,"篮球"),(2,"足球"),(3,"乒乓球"),),initial=[1,2],# 默认选中1,2 Widget=forms.Widgets.CheckBoxSelectMultiple(),) """radioSelect(等价于<input type="radio">)""" gender = forms.fIElds.ChoiceFIEld( label="性别","男"),"女"),"阴阳人"),initial=1,# 默认选中1 Widget=forms.Widgets.RadioSelect(),) """Select标签""" hobby02 = forms.fIElds.ChoiceFIEld( choices=((1,"双色球"),label="爱好02",initial=3,# # 默认选中3 # Widget=forms.Widgets.Select(),# 实现单选Select Widget=forms.Widgets.SelectMultiple(),# 实现多选Select ) Form组件中所有内置字段 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,最小值 max_digits=None,总长度 decimal_places=None,小数位长度 BaseTemporalFIEld(FIEld) input_formats=None 时间格式化 DateFIEld(BaseTemporalFIEld) 格式:2015-09-01TimeFIEld(BaseTemporalFIEld) 格式:11:12DateTimeFIEld(BaseTemporalFIEld)格式:2015-09-01 11:12 DurationFIEld(FIEld) 时间间隔:%d %H:%M:%s.%f ... RegexFIEld(CharFIEld) regex,自定制正则表达式 max_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,帮助提示 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类型 从数据库中获取数据 在使用选择标签时,需要注意choices的选项可以从数据库中获取,但由于是静态字段,==获取的值无法实施更新==,所以需要自定义构造方法从而达到此目的.
from django import formsfrom blog01 import modelsclass RegForm(forms.Form): hobby03 = forms.fIElds.ChoiceFIEld( label="爱好03",# choices=models.Hobby.objects.values_List('ID','name'),Widget=forms.Widgets.CheckBoxSelectMultiple(),) def __init__(self,*args,**kwargs): super(RegForm,self).__init__(*args,**kwargs) # self.fIElds['hobby03'].choices = ((1,'Python'),'Django'),) self.fIElds['hobby03'].choices = models.Hobby.objects.values_List('ID','name') 校验示例 检验手机号是否合法 视图文件:
from django.shortcuts import render,httpResponsefrom blog01 import forms # 导入form文件def register(request): form_obj = forms.RegForm() if request.method == 'POST': form_obj = forms.RegForm(request.POST) if form_obj.is_valID(): # 只有执行了is_valID之后,才可执行cleaned_data,否则会报错 # cleaned_data的数据是经过校验的 print(form_obj.cleaned_data) return httpResponse("注册成功!") return render(request,{'form': form_obj}) HTML文件:
<body>{# novalIDate:阻止验证(form组件会自动验证)#}<form action="" method="post" novalIDate> {% csrf_token %} <p> {{ form.phone.label }} {{ form.phone }} <span >{{ form.phone.errors.0 }}</span> </p> <button>注册</button></form></body> 方式一(基本 *** 作) form文件:
from django import formsfrom django.core.valIDators import RegexValIDatorclass RegForm(forms.Form): phone = forms.fIElds.CharFIEld( label="手机号",valIDators=[ RegexValIDator(r'^1[3-9]\d{9}$',"号码不合法") # RegexValIDator(r"正则表达式","错误提示信息") ],) 方式二(自定义验证规则) form文件:
import refrom django.forms import Formfrom django.forms import Widgetsfrom django.forms import fIEldsfrom 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 RegForm(Form): phone = fIElds.CharFIEld( label="手机号",# 使用自定义验证规则 # valIDators=[校验器函数1,校验器函数2] valIDators=[mobile_valIDate,],error_messages={'required': "手机号不能为空",Widget=Widgets.Textinput( attrs={'class': 'form-control','placeholder': u"手机号码"},) ) 方式三(利用钩子) forms文件:
import refrom django.forms import Formfrom django.forms import Widgetsfrom django.core.exceptions import ValIDationErrorclass RegForm(Form): phone = forms.fIElds.CharFIEld( label="手机号",) ) def clean_phone(self): value = self.cleaned_data.get('phone') mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if mobile_re.match(value): return value raise ValIDationError("手机号不合法") 验证密码一致性 视图文件同上??
form文件:
from django.forms import Formfrom django.core.valIDators import RegexValIDatorclass RegForm(Form): pwd = forms.CharFIEld( label="密码",Widget=Widgets.Passwordinput(),) re_pwd = forms.CharFIEld( label="确认密码",) def clean_re_pwd(self): pwd = self.cleaned_data.get('pwd') re_pwd = self.cleaned_data.get('re_pwd') if pwd == re_pwd: return re_pwd raise ValIDationError("密码不一致") HTML文件:
<body>{# novalIDate:阻止验证(form组件会自动验证)#}<form action="" method="post" novalIDate> {% csrf_token %} {# {{ form.as_p }} 以p标签的形式自动生成 #} <p> {{ form.pwd.label }} {{ form.pwd }} <span >{{ form.pwd.errors.0 }}</span> </p> <p> {{ form.re_pwd.label }} {{ form.re_pwd }} <span >{{ form.re_pwd.errors.0 }}</span> </p> <button>注册</button></form></body> 钩子 局部钩子 from django.forms import Formclass RegForm(Form): test01 = forms.CharFIEld() test02 = forms.CharFIEld() test03 = forms.CharFIEld() # 局部钩子 def clean_test02(self): test01 = self.cleaned_data.get('test01') test02 = self.cleaned_data.get('test02') test03 = self.cleaned_data.get('test03') print(test01,test02,test03) # test03的值定会为None return test02 """ 这里定义的是test02的钩子 ! 定义哪个字段的钩子,就得返回哪个字段的值 此时的钩子只能获取test01与test02的值,而test03的值为None 因为test03字段在test02字段的下面,所以test02的钩子无法获取test03的值(更多可看源码) """ 全局钩子 from django.forms import Formclass RegForm(Form): test01 = forms.CharFIEld() test02 = forms.CharFIEld() test03 = forms.CharFIEld() # 全局钩子 def clean(self): test01 = self.cleaned_data.get('test01') test02 = self.cleaned_data.get('test02') test03 = self.cleaned_data.get('test03') print(test01,test03) return self.cleaned_data """ 这里定义的是全局钩子 ! 定义全局钩子,要返回self.cleaned_data的数据 此时的钩子可以获取所有字段的值 """ 进阶 批量添加样式 通过重写form类的init方法来实现.
from django.forms import Formclass RegForm(Form): test01 = forms.CharFIEld() test02 = forms.CharFIEld() test03 = forms.CharFIEld() def __init__(self,**kwargs) for fIEld in iter(self.fIElds): self.fIElds[fIEld].Widget.attrs.update( { 'class': 'form-control','placeholder': "test",} ) ModelForm form 与 model 的终结结合
==结合后将使用数据库字段的规则==
Form校验文件:
from django import formsfrom django.core.exceptions import ValIDationError # 用于返回错误信息from . import modelsclass BaseForm(forms.ModelForm): # 重写父类的init方法来批量添加样式 def __init__(self,**kwargs): super(BaseForm,**kwargs) for fIEld in iter(self.fIElds): self.fIElds[fIEld].Widget.attrs.update({"class": "input"})# 注册Formclass RegForm(BaseForm): class Meta: # 指定数据表 model = models.UserProfile # 指定要校验的字段,如果指定为 "__all__",则校验所有的字段;如果指定为列表,则只校验列表内的字段 fIElds = ["username","password","email"] # 提示信息 labels = { "username": "用户名","password": "密码","email": "邮箱",} # 自定义错误信息 error_messages = { "username": { "required": "请输入用户名" },"password": { "required": "请输入密码","email": { "required": "请输入邮箱地址","invalID": "邮箱格式错误",} } # 自定义插件 Widgets = { "username": forms.Widgets.Textinput( attrs={ "ID": "reg_username",} ),"password": forms.Widgets.Passwordinput( attrs={ "ID": "reg_password",# 指定input框的type类型为password,并添加ID属性及值 } # 帮助信息 help_texts = {} # 确认密码 re_password = forms.CharFIEld( label="确认密码",error_messages= { "required": "",Widget=forms.Widgets.Passwordinput( attrs={ "ID": "reg_re_password",} ),) # 用于校验密码格式 def clean_password(self): password = self.cleaned_data.get("password") if len(password) == 32: # 前端用md5加密后的固定长度 return password raise ValIDationError("密码格式错误!") # 用于校验密码一致性 def clean_re_password(self): """ 局部钩子:clean_字段名 :return: 定义哪个字段的钩子,就得返回哪个字段的值 """ password = self.cleaned_data.get("password") re_password = self.cleaned_data.get("re_password") if not password or password == re_password: # not password:如果clean_password函数校验失败,则password为空 return re_password raise ValIDationError("密码不一致!")"""class Meta常见参数如下:model = models.Student # 对应的Model中的类fIElds = "__all__" # 字段,如果是__all__,就是表示列出所有的字段;如果是列表,则只使用列表内的字段exclude = [] # 排除的字段labels = None # 提示信息help_texts = None # 帮助提示信息Widgets = None # 自定义插件error_messages = None # 自定义错误信息""" 视图文件:
# 部分相关的代码如下:if reg_form.is_valID(): # 成功校验数据后,才可执行reg_form.cleaned_data obj = reg_form.save(commit=False) # Form组件自带的方法,commit=False表示稍后通过obj.save()方法保存数据 obj.set_password(obj.password) # 设置用户密码 obj.blog_path = obj.username obj.nickname = obj.username obj.save() # 保存 # data = reg_form.cleaned_data # 只有执行了reg_form.is_valID()后才可执行reg_form.cleaned_dataForm套Form
视图文件:
# 生成每行可编辑的form套form的表单from django.forms import modelformset_factory def study_record(request,course_ID): FormSet = modelformset_factory(models.StudyRecord,StudyRecordForm,extra=0) # 会自动在表单下面多生成一个form > extra=0:不生成 queryset = models.StudyRecord.objects.filter(course_record_ID=course_ID) form_set = FormSet(queryset=queryset) return render(request,'crm/sutdy_record_List.HTML',{'form_set': form_set}) HTML文件:
{% for form in form_set %} <tr> {{ form.ID }} <td >{{ form.student }}</td> {# 可禁用编辑#} <td>{{ forloop.counter }}</td> <td>{{ form.instance.student.name }}</td> <td>{{ form.attendance }}</td> <td>{{ form.score }}</td> <td>{{ form.homework_note }}</td> </tr>{% endfor %} 总结 以上是内存溢出为你收集整理的【Django】Form组件全部内容,希望文章能够帮你解决【Django】Form组件所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)