django表单使用

一、表单常用字段类型及参数

表单可以自动生成html代码,每一个字段默认有一个html显示样式,大多数默认为输入框。

字段相当于正则表达式的集合,能够对表单传入的数据进行校验,并且某一部分校验失败时会保留另一部分校验成功的值。

使用表单时首先需要导入forms模块和forms的fields模块,再定义一个继承forms.Form的类,实例化后在模板中通过调用实例化对象的属性生成输入框。

field:这个一般不直接使用,用于被其他字段继承

required=True, 是否允许为空

label=None, 用于生成显示内容,如果不定义label,则显示的内容为首字母大写的字段名

initial=None, 初始值

help_text='', 帮助信息(在标签旁边显示)

error_messages=None, 例如 {'required': '不能为空', 'invalid': '格式错误'},是一个字典,key表示每一个表达式的code,value表示如果在对应的code上发生错误,后台可以捕捉到的错误信息并返给前台与用户交互,其中value又是一个列表

show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)

validators=[], 自定义验证规则

localize=False, 是否支持本地化

disabled=False, 是否可以编辑

label_suffix=None Label内容后缀

widget=None, 生成HTML插件

1.BooleanField(Field):布尔值,相当于单选框

2.CharField(Field):字符串

max_length最大长度,min_length最小长度,strip是否移除用户输入的空格

3.EmailField(CharField):邮箱

invalid格式是否合法

4.IntegerField(Field):整数

invalid格式是否合法、max_value最大值、min_value最小值

5.FloatField(IntegerField):浮点类型

6.DecimalField(IntegerField):浮点类型

max_digits(总长度)、decimal_places(小数位长度)

7.FileField(Field):上传文件、ImageField(Field)上传图片

allow_empty_file是否允许空文件,上传文件需要在form表单指定enctype="multipart/form-data",并且要通过request.FILES接收

upload_to:指定上传路径

8.ChoiceField(Field):单选下拉列表

9.MultipleChoiceField(ChoiceField):多选下拉列表

10.TypedChoiceField(ChoiceField))

可对传入的数据进行一次类型转化coerce = lambda x: int(x)

11.GenericIPAddressField(CharField):ip地址

protocol='both'表示同时支持ipv4和ipv6的地址

12.DateField(BaseTemporalField),日期,2019-05-10,

13.TimeField(BaseTemporalField),时间,14:23

14.DateTimeField(BaseTemporalField),日期和时间,2019-05-10 14:23

15.URLField:接收URL格式的字符串

二、django内置插件

使用django的内置html插件时,需要先导入forms模块的widgets模块,from django.forms import widgets。

对于CharField字段,默认显示的是文本框,如果希望显示成单选、多选或下拉列表的形式,则需要用到widgets定制插件。

TextInput(Input)
EmailInput(TextInput)
NumberInput(TextInput)
RadioSelect(ChoiceWidget)
Select(ChoiceWidget)
SelectMultiple(Select)
CheckboxInput(Input)
CheckboxSelectMultiple(ChoiceWidget)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
URLInput(TextInput)
PasswordInput(TextInput)
FileInput
HiddenInput(TextInput)
NullBooleanSelect
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

1.定制单选radio、单选下拉列表、多选下拉列表、单选框和多选框:通过CharField、ChoiceField和MutipleChoiceField字段

对于单选radio,第一种写法使用CharField字段,该字段默认显示为输入框,通过widget=widgets.RadioSelect插件定制为单选框样式,并将choices作为参数传递给该插件

第二种写法使用ChoiceField字段,该字段默认显示为下拉列表,通过widget=widgets.RadioSelect插件定制为单选框样式,并将choices作为参数传递给该字段

通过widgets定制插件时,可同时给字段加上自定义属性,例如如下hobby8和hobby9。

#单选radio
hobby1 = fields.CharField(label='爱好1',widget=widgets.RadioSelect(choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'))),initial=1)
hobby2 = fields.ChoiceField(label='爱好2',widget=widgets.RadioSelect,choices=((1,'篮球'),(2,'足球'),(3,'乒乓球')),initial=1)
#单选下拉列表
hobby3 = fields.CharField(label='爱好3',widget=widgets.Select(choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'))),initial=3)
hobby4 = fields.ChoiceField(label='爱好4', widget=widgets.Select,choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')), initial=3)
#多选下拉列表
hobby5 = fields.CharField(label='爱好5', widget=widgets.SelectMultiple(choices=((1, '篮球'), (2, '足球'), (3, '乒乓球'))), initial=[1, 2])
hobby6 = fields.MultipleChoiceField(label='爱好6', widget=widgets.SelectMultiple,choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')), initial=[1,2])
#单选框
hobby7 = fields.CharField(label='是否同意',widget=widgets.CheckboxInput())
#多选框
hobby8 = fields.CharField(label='爱好8', widget=widgets.CheckboxSelectMultiple(choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')),attrs={'name':'hobby8'}), initial=[1, 2])
hobby9 = fields.MultipleChoiceField(label='爱好9',widget=widgets.CheckboxSelectMultiple(attrs={'name':'hobby9'}),choices=((1, '篮球'), (2, '足球'), (3,'乒乓球'),initial=[1, 2]) 
定制radio、select和checkbox

        

2.扩展正则

如果某一字段自带的验证方法不足以进行验证,可以自定义验证方法,这需要通过RegexField字段或者validators=[]参数完成

#单选radio
hobby1 = fields.CharField(label='爱好1',widget=widgets.RadioSelect(choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'))),initial=1)
hobby2 = fields.ChoiceField(label='爱好2',widget=widgets.RadioSelect,choices=((1,'篮球'),(2,'足球'),(3,'乒乓球')),initial=1)
#单选下拉列表
hobby3 = fields.CharField(label='爱好3',widget=widgets.Select(choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'))),initial=3)
hobby4 = fields.ChoiceField(label='爱好4', widget=widgets.Select,choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')), initial=3)
#多选下拉列表
hobby5 = fields.CharField(label='爱好5', widget=widgets.SelectMultiple(choices=((1, '篮球'), (2, '足球'), (3, '乒乓球'))), initial=[1, 2])
hobby6 = fields.MultipleChoiceField(label='爱好6', widget=widgets.SelectMultiple,choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')), initial=[1,2])
#单选框
hobby7 = fields.CharField(label='是否同意',widget=widgets.CheckboxInput())
#多选框
hobby8 = fields.CharField(label='爱好8', widget=widgets.CheckboxSelectMultiple(choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')),
attrs={'name':'hobby7'}), initial=[1, 2])
hobby9 = fields.MultipleChoiceField(label='爱好9',widget=widgets.CheckboxSelectMultiple(attrs={'name':'hobby8'}),
choices=((1, '篮球'), (2, '足球'), (3,'乒乓球'),initial=[1, 2]) 
定制radio、select和checkbox

通过validators=[]属性定制时,可以自定义多个规则RegexValidator,每一个规则的第一个参数为规则,第二个规则为对应的错误信息

通过RegexField字段定制时,只能定制一个规则。

三、表单使用实例

1.forms的py文件

class UserForm(forms.Form):
    username = fields.CharField(label='姓名',required=True,max_length=15,error_messages={'max_length':'too long'})
    age = fields.IntegerField(label='年龄',required=True,min_value=18,error_messages={'invalid':'请输入整数','min_value':'不符合劳动法'})
    birth = fields.DateField(label='入职时间',required=True)
    email = fields.EmailField(label='邮箱',required=True,error_messages={'invalid':'请输入有效格式的邮箱'})
    gender = fields.CharField(label='性别', widget=widgets.RadioSelect(choices=((1, ''), (2, ''))), initial=1)
    resume = fields.FileField(label='简历')
    city = fields.CharField(label='省份',widget=widgets.Select())
    hobby = fields.MultipleChoiceField(label='爱好',widget=widgets.CheckboxSelectMultiple(attrs={'name':'hobby8'}),
choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')),initial=[1,2])
    proto = fields.CharField(label='是否已阅协议', widget=widgets.CheckboxInput())
    def __init__(self,*args,**kwargs):
        super(UserForm,self).__init__(*args,**kwargs)
        self.fields['city'].widget.choices = Province.objects.all().values_list()
#假设定义了一个省份的类存放在数据库,为了数据库的内容变化能在页面刷新时显示到页面上,需要进行init操作并将数据库的值赋值给city字段
定义UserForm

2.处理函数的py文件

def add_user(request):
    if request.method == 'GET':
        obj = UserForm()  #实例化一个空的表单
        return render(request,'add_user.html',{'obj':obj})
    elif request.method =='POST':
        obj = UserForm(request.POST,request.FILES) #传入的文件需要通过request.FILES接收,其他通过request.POST接收,一起传递给表单类进行实例化
        if obj.is_valid(): #判断输入是否有效
            print(type(obj.fields))
            print(obj.fields)
            print(type(obj.cleaned_data))
            print(obj.cleaned_data) #打印输入内容
            print(obj.cleaned_data['username'])  #获取输入的username值
            print(obj.cleaned_data.get('email'))  #获取输入的email值
            UserInfo.object.create(**obj.cleaned.data)  # UserForm表单对应了数据库中的表UserInfo
        else:  
            print(type(obj.errors))
            print(obj.errors.get_json_data())#打印错误信息,如果需要打印错误信息,还需要在form中指定novalidate属性
        return render(request,'add_user.html',{'obj':obj})
    else:
        return redirect('http://www.baidu.com')
处理函数

①obj.is_valid()方法

obj.is_valid()表示判断输入是否满足Form各字段的要求,实例化一个非空的表单,在实例化的时候并没有生成html标签,也没有进行表单验证,生成html标签并且进行表单验证是在is_valid()时进行的。obj.cleaned_data表示键值和对应的输入值。

如果在实例化表单的时候通过inital传值,即obj = UserForm(inital = (request.POST,request.FILES) ),在实例化的时候不会进行表单验证。

②obj.fields属性

obj.fields表示表单的所有字段,类型为<class 'collections.OrderedDict'>。

③obj.cleaned_data属性

在is_valid之前没有cleaned_data,cleaned_data是在进行验证之后才生成,类型为<class 'dict'>

④obj.errors

obj.errors表示错误信息,类型为<class 'django.forms.utils.ErrorDict'>

错误信息默认是以as_ul()进行显示的,其他显示方式还有as_data()、as_json()、as_text()、get_json_Data(),常用get_json_Data()。

3.模板文件

在渲染form对象时,可以以as_table表格、as_ul无序列表、as_p段落等方式进行渲染。

<form action="add_user" method="post" enctype="multipart/form-data">  <!--如果需要上传文件,则form中应指定enctype属性为multipart/form-data-->
        {% csrf_token %}
        <table>
            {{ obj.as_table }} <!--将表单以表格形式渲染-->
        </table>
        <input type="submit">
    </form>
模板文件

页面显示内容为,并且如果按照要求输入数据,pycharm打印的信息如下。

 

如果在form中指定invalidate属性,假设不输入年龄、不按格式输入邮箱,那么打印的错误信息如下

 

另外一种模板渲染方式

<form action="add_user" method="post" enctype="multipart/form-data" novalidate>  
    <!--如果需要上传文件,则form中应指定enctype属性为multipart/form-data-->
        {% csrf_token %}
         <p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.0 }}</p>
         <p>{{ obj.age.label }}{{ obj.age }}{{ obj.errors.0 }}</p>
         <p>{{ obj.birth.label }}{{ obj.birth }}{{ obj.errors.0 }}</p>
         <p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.0 }}</p>
         <p>{{ obj.gender.label }}{{ obj.gender }}{{ obj.errors.0 }}</p>
         <p>{{ obj.resume.label }}{{ obj.resume }}{{ obj.errors.0 }}</p>
         <p>{{ obj.city.label }}{{ obj.city }}{{ obj.errors.0 }}</p>
         <p>{{ obj.hobby.label }}{{ obj.hobby }}{{ obj.errors.0 }}</p>
         <p>{{ obj.proto.label }}{{ obj.proto }}{{ obj.errors.0 }}</p>
        <input type="submit">
</form>
另一种模板渲染方式

四、表单与数据库是否重复验证

上述方法已经可以可以对各字段进行格式、大小、长度等验证,但是表单提交的数据通常要写入数据库,为了防止写入违反唯一性约束的两条相同记录,还需要验证增加的数据是否已经在数据库中存在。

1.对于单一字段

可在表单类时同时定义表单的方法,方法名称为clean_验证字段名,假如上述例子UserForm表单对应了的数据库中的表UserInfo,假如UserInfo表中的username不可重复,那么在定义表单时可通过增加clean_username()方法实现。

#from django.core.exceptions import ValidationError导入异常类
class UserForm(forms.Form):
    username = fields.CharField(label='姓名',required=True,max_length=15,error_messages={'max_length':'too long'})
    ……
    def clean_username(self):  #定义clean_字段名的方法
        v= self.cleaned_data['username']  #
        if UserInfo.objects.filter(username=v).count():  #
            raise ValidationError('用户名已经存在','repeat') #抛出异常,第一个参数为error_message,第二个为code
        return v
表单对单一字段验证

2.对于多个字段

在定义表单类的同时定义clean()方法,假如username和age字段不可同时重复

#from django.core.exceptions import NON_FIELD_ERRORS, ValidationError  
class UserForm(forms.Form):
    ……  
    def clean(self):
        value_dic = self.cleaned_data
        v1 = value_dic.get('username')
        v2 = value_dic.get('email')
        if UserInfo.objects.filter(username=v1,email=v2).count():
            raise ValidationError('total error')
        return value_dic
表单对多个字段验证

因为这一类错误不属于单一的字段,因此在errors中显示的错误字段为__all__(也即NON_FIELD_ERRORS),而在模板页面只能通过v.non_field_errors(小写)获取整体错误信息,不能通过v.__all__获取。

 

 

 

 

 

 

 

 

表单字段类型可参考http://www.cnblogs.com/wupeiqi/articles/6144178.html

 

posted @ 2018-12-27 11:18  Forever77  阅读(360)  评论(0编辑  收藏  举报