Django - Forms组件

目录

一、数据校验功能

1-1 自定义局部校验功能(局部钩子) - 单个属性校验

1-2 自定义全局校验功能(全局钩子) - 多个属性校验

 二、模板渲染功能 - 三种方式

渲染方式一、使用获取的myform对象进行属性获取 - 灵活性最高

渲染方式二、 对获取的myform对象进行循环取值 - 建议使用

渲染方式三、使用源码内提供属性as_p、as_ul -- (不推荐使用)

2-1 Django类创建 - 内置字段

2-2 form内widget属性

2-3 常用选择属性 - radio、select、checkbox

 三、模板错误信息渲染(form形式提交数据)


一、数据校验功能

总结:

  • form对象.is_valid() -- 返回true表示数据校验通过
  • form对象.errors -- 继承于字典,保存了所有错误信息 - {‘name’:[错误信息1,错误信息2,]}
  • 字段.errors -- 每个字段的错误信息列表
  1. 导入模块 - from django import forms

  2. 类继承 forms.Form
    注意:

     - 内部属性名必须和前端的name一一对应
     - 若前端form内的存在name字段在类中不存在,则跳过校验 
    - 若后台类内的属性在前端内未定义,则校验失败

    from django import forms
    
    class MyForm(forms.Form):
    	# 定义属性,可以用来检验字符串类型
    	# 限制最大长度是8,最小长度是3
    	name = forms.CharField(max_length = 8,min_length = 3)
            # required  -- 默认为True,表示是否必填
    	pwd = forms.CharField(max_length = 8,min_length = 3,required=True)
    	
    	# 校验是否是邮箱格式
    	email = forms.EmailField()

     

  3. 在函数内实例化上述类对象

    注意:
    若前台使用ajax而不是form传值,则将传过来的字典类型数据扔给myform = MyForm()

    def index_form(request):
        
        if request.method =='GET':
            return render(request,'index.html')
        
        # 生成实例化对象,需要传入要校验的数据(字典)
        # dic = {'name':'n1','pwd':'123','email':'111',}
        # myform = MyForm(dic)
        
        myform = MyForm(request.POST)
        # is_valid()方法用于返回是否校验成功
        if myform.is_valid():
            # cleaned_data属性表示校验通过的数据 -- 本质是字典
            print(myform.cleaned_data)
            return HttpResponse('校验成功')
        else:
            # errors属性表示错误的信息 -- 本质是一个字典(ErrorDict)
            print(myform.errors)
            print(myform.errors.as_data()) 
            # errors对象内 as_data()方法返回错误信息内容 {'name':[V…Error(['……',])]}
            return HttpResponse('校验失败')

     

  4. 前端使用form表单提交数据
    注意:前端form内的存在name字段,可以在在类中不被定义;但是类中被定义的属性,前端必须有对于name字段

    <form action="" method="post">
    
        <p>用户名: <input type="text" name="name"></p>
        <p>密码: <input type="text" name="pwd"></p>
        <p>确认密码: <input type="text" name="re_pwd"></p>
        <p>邮箱: <input type="text" name="email"></p>
        <input type="submit" value="提交">
    
    </form>

1-1 自定义局部校验功能(局部钩子) - 单个属性校验

  • myForm类内定义函数 : clean_类内属性名
  • 函数内部使用 self.cleaned_data.get('字段名') 取出字段进行校验规则书写
  • 错误抛出 ValidationError('错误信息') -- 需要导入相应模块
  • 校验完成,函数返回被校验字段
  • !!!!注意!!!!:自定义局部钩子函数命名规则:clean_类内对应字段名
from django import forms
from django.core.exceptions import ValidationError

class MyForm(forms.Form):
	name = forms.CharField(max_length = 8,min_length = 3)
	pwd = forms.CharField(max_length = 8,min_length = 3,required=True)
	email = forms.EmailField()

    # 针对class内name属性的校验规则,完成了默认规则校验之后的自定义校验
    def clean_name(self):
        # self:当前form对象

        name = self.cleaned_data.get('name')
        if name.startswith('sb'):
            # 失败,抛异常
            raise ValidationError('不能以sb开头')
        # 正常,把name返回
        return name    

1-2 自定义全局校验功能(全局钩子) - 多个属性校验

  • myForm类内重写clean方法
  • 函数内部使用 self.cleaned_data.get('字段名') 取出字段进行校验规则书写
  • 错误抛出 ValidationError('错误信息') -- 需要导入相应模块
  • 校验完成,函数返回cleanned_data
  • !!!!注意!!!!:自定义全局钩子函数必须以clean命名,即重写clean方法!
from django import forms
from django.core.exceptions import ValidationError

class MyForm(forms.Form):
	name = forms.CharField(max_length = 8,min_length = 3)
	pwd = forms.CharField(max_length = 8,min_length = 3,required=True)
    re_pwd = forms.CharField(max_length = 8,min_length = 3,required=True)
	email = forms.EmailField()

    # 针对class内name属性的校验规则,完成了默认规则校验之后的自定义校验
    def clean_name(self):
        # self:当前form对象

        name = self.cleaned_data.get('name')
        if name.startswith('sb'):
            # 失败,抛异常
            raise ValidationError('不能以sb开头')
        # 正常,把name返回
        return name

    # 针对全局数据的校验规则,单独self.cleaned_data.get('')获取对象值进行规则书写
    # 只有通过了默认规则的校验和单个校验后进行全局校验
    def clean(self):

        pwd=self.cleaned_data.get('pwd')
        re_pwd=self.cleaned_data.get('re_pwd')

        if pwd==re_pwd:
            # 返回 self.cleaned_data - 校验通过的数据
            return self.cleaned_data
        else:
            raise ValidationError('两次密码不一致')    

 

 二、模板渲染功能 - 三种方式

  1. 在视图层实例化对象  myform=MyForm() -- 传输内容表示需要校验的数据,若只渲染无需填入
  2. 通过 render 将实例化对象内的属性返回给需要渲染的页面
    # 渲染模板
    def index_form(request):
        # 生成对象时(实例化),需要传入要校验的数据(字典)
        myform=MyForm()
        if request.method=='GET':
            return render(request,'indxe2.html',locals())

     

  3. 前端进行渲染操作

渲染方式一、使用获取的myform对象进行属性获取 - 灵活性最高

<form action="" method="post" >
    <p>用户名: {{ myform.name }}</p>
    <p>密码: {{ myform.pwd }}</p>
    <p>邮箱: {{ myform.email }}</p>
    <input type="submit" value="提交">
</form>

渲染方式二、 对获取的myform对象进行循环取值 - 建议使用

注意:

  • foo.label 属性表示类内属性的标签名,可在class内进行定义
  • foo 对象会自动在页面上呈现为一个input输入框,即是在class内定义的属性类型
  • 若想要修改foo对象在页面的显示样式(例如css样式或pwd隐藏),需要使用widget参数进行配置,详见2-2
<form action="" method="post" >
    {% for foo in myform %}
        <p>{{ foo.label }}:{{ foo }}</p>
    {% endfor %}

    <input type="submit" value="提交">
</form>
from django import forms

class MyForm(forms.Form):
    name = forms.CharField( max_length=8, min_length=3, label='用户名',)
    pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密码',)
    re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='确认密码',)
    email = forms.EmailField(label='邮箱',)

渲染方式三、使用源码内提供属性as_p、as_ul -- (不推荐使用)

<form action="" method="post" >
    {{ myform.as_p }}
    <hr>
    {{ myform.as_ul }}
    <input type="submit" value="提交">
</form>

2-1 Django类创建 - 内置字段

Field 
required=True是否允许为空
widget=NoneHTML插件
label=None用于生成Label标签或显示内容
initial=None初始值
help_text='帮助信息(在标签旁边显示)
error_messages=None错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[]自定义验证规则
localize=False是否支持本地化(根据不同语言地区访问用户显示不同语言)
disabled=False是否可以编辑
label_suffix=Noneabel内容后缀
CharField(Field) 
max_length=None最大长度
min_length=None最小长度
strip=True是否移除用户输入空白
IntegerField(Field) 
max_value=None最大值
min_value=None最小值
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': '...'}
FileField(Field) 
allow_empty_file=False是否允许空文件
ImageField(FileField)需要PIL模块,pip3 install Pillow
ChoiceField(Field) 
choices=()选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True是否必填
widget=None插件,默认select插件
label=NoneLabel内容
initial=None初始值
help_text=''帮助提示
TypedChoiceField(ChoiceField) 
coerce = lambda val: val对选中的值进行一次转换,通过lambda函数实现
empty_value= ''空值的默认值
MultipleChoiceField(ChoiceField)多选框
TypedMultipleChoiceField(MultipleChoiceField) 
coerce = lambda val: val对选中的每一个值进行一次转换
empty_value= ''空值的默认值
ComboField(Field) 
fields=()使用多个验证,<br />如下:即验证最大长度20,又验证邮箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合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类型
注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串
  
NullBooleanField(BooleanField) 
BooleanField(Field) 
URLField(Field) 
EmailField(CharField) 
**FloatField(IntegerField)** 
  

2-2 form内widget属性

TextInput(Input)input type="text"
NumberInput(TextInput)数字输入框
EmailInput(TextInput)邮箱输入框
URLInput(TextInput)url输入框
PasswordInput(TextInput)密码输入框
HiddenInput(TextInput)隐藏输入框
Textarea(Widget)textarea文本区
DateInput(DateTimeBaseInput)日期输入框
DateTimeInput(DateTimeBaseInput)日期时间输入框
TimeInput(DateTimeBaseInput)时间输入框
CheckboxInput多选框
Select下拉框
NullBooleanSelect非空布尔值下拉框
SelectMultiple多选下拉框
RadioSelect单选框
CheckboxSelectMultiple多选checkbox ???
FileInput文件上传
ClearableFileInput MultipleHiddenInput多隐藏输入框
SplitDateTimeWidget时间分割框(两个input框)
SplitHiddenDateTimeWidget 
SelectDateWidget 
  

2-3 常用选择属性 - radio、select、checkbox

# 单 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,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)

# 单 select,值为字符串
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.Select
)

# 多选 select,值为列表
user = fields.MultipleChoiceField(
    choices=((1,'上海'),(2,'北京'),),
    initial=[1,],
    widget=widgets.SelectMultiple
)



# 单 checkbox
user = fields.CharField(
    widget=widgets.CheckboxInput()
)


# 多选 checkbox,值为列表
user = fields.MultipleChoiceField(
    initial=[2, ],
    choices=((1, '上海'), (2, '北京'),),
    widget=widgets.CheckboxSelectMultiple
class MyForm(forms.Form):
    name = forms.CharField(max_length=8, min_length=3, label='用户名',
                           widget=forms.widgets.TextInput(
                        attrs={'class': 'form-control'} # 使用 attrs 修改id、class等内容
                                ))
    pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密码',
                          widget=forms.widgets.PasswordInput())
    re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='确认密码',
                             widget=forms.widgets.PasswordInput())
    email = forms.EmailField(label='邮箱',
                             widget=forms.widgets.EmailInput())
    url = forms.URLField(widget=forms.widgets.URLInput())
    file = forms.FileField(widget=forms.widgets.FileInput())
    chock_box = forms.CharField(widget=forms.widgets.CheckboxInput())
    select_box = forms.CharField(widget=forms.widgets.CheckboxSelectMultiple(
                                                choices=((1,'上海'),(1,'北京'))))

 

 三、模板错误信息渲染(form形式提交数据)

注意:

  • novalidate - 取消浏览器自带的校验信息,为了测试错误信息在form提交之后显示 
  • 前端使用 foo.errors.0 获取抛出的错误信息
  • 类内定义字段时使用 error_messages 重写默认校验错误信息
  • 全局钩子函数中的错误会放入__all__对象内
from django.shortcuts import render, HttpResponse

# Create your views here.
from django import forms
from django.core.exceptions import ValidationError


class MyForm(forms.Form):
    name = forms.CharField(max_length=8, min_length=3, label='用户名',
                           widget=forms.widgets.TextInput(),
                           error_messages={'max_length': '超出长度范围,8',
                                           'min_length': '小于长度范围,3',
                                           'required': '必填选项',
                                           })
    pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密码',
                          widget=forms.widgets.PasswordInput(),
                          error_messages={'max_length': '超出长度范围,8',
                                          'min_length': '小于长度范围,3',
                                          'required': '必填选项',
                                          }
                          )
    re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='确认密码',
                             widget=forms.widgets.PasswordInput(),
                             error_messages={'max_length': '超出长度范围,8',
                                             'min_length': '小于长度范围,3',
                                             'required': '必填选项',
                                             }
                             )
    email = forms.EmailField(label='邮箱',
                             error_messages={'required': '必填选项', 'invalid': '非法格式'}
                             )

    # 用户名校验
    def clean_name(self):
        name = self.cleaned_data.get('name')
        if name.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return name

    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        re_pwd = self.cleaned_data.get('re_pwd')
        if pwd == re_pwd:
            return self.cleaned_data
        else:
            raise ValidationError('两次密码不一致')


def view_form(request):
    if request.method == 'GET':
        myform = MyForm()
    elif request.method == 'POST':
        myform = MyForm(request.POST)
        if myform.is_valid():
            return HttpResponse('登陆成功')
        else:
            # 全局钩子的ValidationError 自定义错误被保存在nyform对象errors的__all__私有属性下
            print(myform.errors)  # ErrorDict : {"校验错误的字段":["错误信息",]}
            # <ul class="errorlist"><li>email<ul class="errorlist"><li>非法格式</li></ul></li><li>__all__<ul class="errorlist nonfield"><li>两次密码不一致</li></ul></li></ul>
            all_error = myform.errors.get('__all__')
            print(all_error)
            # <ul class="errorlist nonfield"><li>两次密码不一致</li></ul>
            if all_error:
                all_error = all_error[0]
                print(all_error)
                # 两次密码不一致
            print(myform.errors.as_data)
            # <bound method ErrorDict.as_data of {'email': ['非法格式'], '__all__': ['两次密码不一致']}>
            print(type(myform.errors.as_data))
            print(myform.errors.as_data())
            # {'email': [ValidationError(['非法格式'])], '__all__': [ValidationError(['两次密码不一致'])]}
    return render(request, 'forms.html', locals())
<form action="" method="post"  novalidate>
    {% for foo in myform %}
        <p>{{ foo.label }}:{{ foo }}<span> {{ foo.errors.0 }}</span> </p>
    {% endfor %}

    <input id = 'btn' type="submit" value="提交">
</form>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值