欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Django教程--Form表单

程序员文章站 2022-04-25 15:17:51
...

Django教程–Form表单

前面我们已经了解如何在django中使用GET、POST传递数据,但是我们并没有对用户提交的数据进行验证(为何需要验证大家都懂得),对于验证我们可以自己写相关代码进行判断(最基本也有效的方法),但是django作为一个集大成的全面框架,为我们提供了一种更优雅简单的方式,那就是今天的主角–Form,Form不仅仅具有数据验证功能,还可以生成用于提交的html标签,接下来我们就来了解一下如何使用Form。


Form基本使用

按照惯例,我们先来段代码演示如何使用,接着前面的PostParams工程,我们在app目录下新建forms.py文件,用来存放Form表单的代码,代码如下:

from django import forms


class RegisterForm(forms.Form):
    username=forms.CharField(label='username',max_length=20,required=True,error_messages={'required':'username cannot be null'})
    password=forms.CharField(label='password',widget=forms.PasswordInput,required=True,error_messages={'required':'password cannot be null'})
    email=forms.EmailField(label='email',required=True,
                            error_messages={'required': u'email cannot be null','invalid': u'email format is wrong'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'email'}))
    image=forms.ImageField(label='headimage',required=False)

从代码可以看到,使用Form我们需要定义一个类继承自forms.Form,然后定义几个变量(forms以经为什么提供了多种输入框,甚至Email都有,对于Email会自己做个正则表达判断),需要注意变量名对应html表单的name属性,每个属性有不同的校验规则(下面会仔细介绍,暂时先具体看下用法),我们还可以自定义每个属性的widget和label(用于生成html标签)以及校验错误返回的信息。
接下来我们在views.py里新建一个视图函数代码如下:

def form_view(request):
    if request.method=='GET':
        register_form=RegisterForm()
        return render(request,'form.html',{'form':register_form})
    else:
        register_form=RegisterForm(request.POST or None,request.FILES or None)
        if register_form.is_valid():
            return HttpResponse('username:'+register_form.cleaned_data['username']+'&password:'+register_form.cleaned_data['password']+'&email:'+register_form.cleaned_data['email'])
        else:
            return render(request, 'form.html', {'form': register_form})

当然我们也要建立对应的模板文件form.html代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" >
    {%csrf_token%}
    <p>{{form.username.label}}:{{form.username}}</p>
    {%if form.errors.username%}
    {{form.errors.username}}
    {%endif%}
    <p>{{form.password.label}}:{{form.password}}</p>
     {%if form.errors.password%}
    {{form.errors.password}}
    {%endif%}
    <p>{{form.email.label}}:{{form.email}}</p>
       {%if form.errors.email%}
    {{form.errors.email}}
    {%endif%}
    <P>{{form.image.label}}:{{form.image}}</P>
     {%if form.errors.image%}
    {{form.errors.image}}
    {%endif%}

    <input type="submit" value="Submit">
</form>

</body>
</html>

然后在urls.py中添加拦截

from django.conf.urls import patterns, include, url
from django.contrib import admin

from app.views import params_test, params_test_reg, params_post, form_view

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'PostParams.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),

    url(r'^admin/', include(admin.site.urls)),
    url(r'^params_test/$',params_test),
    url(r'^params_test_reg/str(?P<str>\w+)page(?P<page>\d+)/$',params_test_reg),
    url(r'^post/$',params_post),
    url(r'^form/$',form_view),
)

启动服务器,输入http://127.0.0.1:8000/form/即可看到对应的表单,输入相关信息然后提交,如果满足验证要求,就会返回输入信息,当不满足的时候就会重新跳回表单界面并提示错误信息。

Form表单代码解析

上面我们已经展示了如何使用Form表单,接下来我们就来分析下上述代码并讲解Form。
先看Forms.py代码,Form为我们提供了格式各样的Field,用于应对各种各样的输入场景,例如本代码里面首先定义了四个需要提交的属性,每个属性各不相同,例如username需要文本输入框使用CharField,password同样需要文本输入框但是需要密码输入框,所以需要设置widget为密码输入框,对于email需要对输入的格式进行验证是否为正确的邮箱,所以需要EmailField,而对于图像文件则有对应的ImageField,对于这些属性我们还可以通过required指定哪些是必须输入(默认为True),我们还可以通过指定error_messages验证错误时显示的信息。
定义好表单后我们需要在视图函数中使用该表单,例如本例中先判断是否为get请求,如果为get请求就创建表单然后传给模板,在模板中我们只需使用{{}}标签输出表单对应的属性,然后就会自动渲染出该属性对应的widget的代码,我们可以更改widget甚至自定义widget来达到自己的个性化网页输入需求,当然我们还要判断当前表单是否有验证错误,如果发生错误该表单的errors即会有对应的错误信息(如form.errors.username)。
当我们提交表单的时候,视图函数通过request.POST(如果提交方式为POST,为GET提交请使用request.GET),request.FILES(如果提交包含文件)自动创建好表单,然后调用is_valid()进行验证表单输入,没有错误则返回输入信息,发生错误就返回表单提交页面并显示错误信息。
也许有人会说这种提交表单的方式过于笨重(在html模板中使用表单属性),不够灵活,有时候灵活和简便是不可多得的,框架提供功能越多,可能导致其更为笨重,但是这里我们也可以不使用这种笨重的方式,我们只需要将html表单里属性的name定义为和Form变量名一样即可,然后可以同样在后台创建接收输入的表单,例如本例html代码可以更改为

<form method="post" enctype="multipart/form-data" >
 {%csrf_token%}
    <p>username:<input id="id_username" maxlength="20" name="username" type="text" /></p>

    <p>password:<input id="id_password" name="password" type="password" /></p>

    <p>email:<input class="form-control" id="id_email" name="email" placeholder="email" type="text" /></p>

    <P>headimage:<input id="id_image" name="image" type="file" /></P>


    <input type="submit" value="Submit">
</form>

后台视图函数不需要任何更改也可正常使用。
对于Form验证Django为我们提供了一些通用的验证机制,如验证属性是否为空(required),长度验证(max_length,min_length),甚至电话号码email验证(EmailField,PhoneField)。

Form自定义验证

form验证流程
Django教程--Form表单
1.函数full_clean()依次调用每个field的clean()函数,该函数针对field的max_length,unique等约束进行验证,如果验证成功则返回值,否则抛出ValidationError错误。如果有值返回,则放入form的cleaned_data字典中。
2.如果每个field的内置clean()函数没有抛出ValidationError错误,则调用以clean_开头,以field名字结尾的自定义field验证函数。验证成功和失败的处理方式同步骤1。
3.最后,调用form的clean()函数——注意,这里是form的clean(),而不是field的clean()——如果clean没有错误,那么它将返回cleaned_data字典。
4.如果到这一步没有ValidationError抛出,那么cleaned_data字典就填满了有效数据。否则cleaned_data不存在,form的另外一个字典errors填上验证错误。在template中,每个field获取自己错误的方式是:{{ form.username.errors }}。
5.最后,如果有错误is_valid()返回False,否则返回True。
对于某些自定义验证规则我们可以通过重载上述clean_field函数或者clean函数来实现,例如对于用户注册需要验证用户名是否存在,两次密码输入是否相等,我们可以通过以下代码实现

from django import forms


class RegisterForm(forms.Form):
    username=forms.CharField(label='username',max_length=20,required=True,error_messages={'required':'username cannot be null'})
    password=forms.CharField(label='password',widget=forms.PasswordInput,required=True,error_messages={'required':'password cannot be null'})
    password1 = forms.CharField(label='password1', widget=forms.PasswordInput, required=True,
                               error_messages={'required': 'password cannot be null'})
    email=forms.EmailField(label='email',required=True,
                            error_messages={'required': u'email cannot be null','invalid': u'email format is wrong'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'email'}))
    image=forms.ImageField(label='headimage',required=False)

    def clean_username(self):
        user = self.cleaned_data.get('username')
        if user == 'cc':
            raise forms.ValidationError('username exsite!')

        return user

    def clean(self):
        cleaned_data = self.cleaned_data
        pwd = cleaned_data['password']

        pwd2 = cleaned_data['password1']
        print(pwd, pwd2)
        if pwd != pwd2:
            raise forms.ValidationError('the password you input is not same')
        return cleaned_data

我们重载clean_username函数来判断提交用户名是否为‘cc’,如果相等则验证失败并提示错误(通过 raise forms.ValidationError(‘username exsite!’)来实现),然后重载clean函数来判断两次输入密码是否相同。

Form文件接收

在上述例子中虽然使用了ImageField,但是并没有演示如何在视图函数中接收文件,对于文件来说我们同样可以通过form.cleaned_data[‘image’]来获取,然后可以获取上传文件的信息和实际文件并可以保存下来,代码如下:

  myFile=register_form.cleaned_data['image']
            destination = open(os.path.join(BASE_DIR, myFile.name), 'wb+')
            for chunk in myFile.chunks():
                destination.write(chunk)
            destination.close()

和前一节的文件提交类似。


经过本节,我们了解了Form的基本使用–创建,渲染以及数据验证,其实Form的功能远不止于此,在后面我们会发现和Model结合Form具有更强大的功能,你只需要少量代码即可完成大量功能,这就是Django这种集大成框架的优势(当然会损失点灵活性),甚至就是python的宗旨(life is short,you need python),今天我们先了解到这里,谢谢大家支持。

参考链接

1.https://www.cnblogs.com/ccorz/p/5868380.html