Django教程--Form表單

Django教程--Form表單

前面我們已經(jīng)了解如何在django中使用GET凌停、POST傳遞數(shù)據(jù),但是我們并沒有對用戶提交的數(shù)據(jù)進(jìn)行驗證(為何需要驗證大家都懂得)隅俘,對于驗證我們可以自己寫相關(guān)代碼進(jìn)行判斷(最基本也有效的方法),但是django作為一個集大成的全面框架,為我們提供了一種更優(yōu)雅簡單的方式断盛,那就是今天的主角--Form,F(xiàn)orm不僅僅具有數(shù)據(jù)驗證功能愉舔,還可以生成用于提交的html標(biāo)簽钢猛,接下來我們就來了解一下如何使用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以經(jīng)為什么提供了多種輸入框馏鹤,甚至Email都有征椒,對于Email會自己做個正則表達(dá)判斷),需要注意變量名對應(yīng)html表單的name屬性湃累,每個屬性有不同的校驗規(guī)則(下面會仔細(xì)介紹勃救,暫時先具體看下用法),我們還可以自定義每個屬性的widget和label(用于生成html標(biāo)簽)以及校驗錯誤返回的信息治力。
接下來我們在views.py里新建一個視圖函數(shù)代碼如下:

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})

當(dāng)然我們也要建立對應(yīng)的模板文件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),
)

啟動服務(wù)器蒙秒,輸入http://127.0.0.1:8000/form/即可看到對應(yīng)的表單,輸入相關(guān)信息然后提交琴许,如果滿足驗證要求税肪,就會返回輸入信息,當(dāng)不滿足的時候就會重新跳回表單界面并提示錯誤信息榜田。

Form表單代碼解析

上面我們已經(jīng)展示了如何使用Form表單益兄,接下來我們就來分析下上述代碼并講解Form。
先看Forms.py代碼箭券,F(xiàn)orm為我們提供了格式各樣的Field净捅,用于應(yīng)對各種各樣的輸入場景,例如本代碼里面首先定義了四個需要提交的屬性辩块,每個屬性各不相同蛔六,例如username需要文本輸入框使用CharField,password同樣需要文本輸入框但是需要密碼輸入框荆永,所以需要設(shè)置widget為密碼輸入框,對于email需要對輸入的格式進(jìn)行驗證是否為正確的郵箱国章,所以需要EmailField,而對于圖像文件則有對應(yīng)的ImageField具钥,對于這些屬性我們還可以通過required指定哪些是必須輸入(默認(rèn)為True),我們還可以通過指定error_messages驗證錯誤時顯示的信息液兽。
定義好表單后我們需要在視圖函數(shù)中使用該表單骂删,例如本例中先判斷是否為get請求,如果為get請求就創(chuàng)建表單然后傳給模板四啰,在模板中我們只需使用{{}}標(biāo)簽輸出表單對應(yīng)的屬性宁玫,然后就會自動渲染出該屬性對應(yīng)的widget的代碼,我們可以更改widget甚至自定義widget來達(dá)到自己的個性化網(wǎng)頁輸入需求柑晒,當(dāng)然我們還要判斷當(dāng)前表單是否有驗證錯誤欧瘪,如果發(fā)生錯誤該表單的errors即會有對應(yīng)的錯誤信息(如form.errors.username)。
當(dāng)我們提交表單的時候匙赞,視圖函數(shù)通過request.POST(如果提交方式為POST,為GET提交請使用request.GET),request.FILES(如果提交包含文件)自動創(chuàng)建好表單佛掖,然后調(diào)用is_valid()進(jìn)行驗證表單輸入,沒有錯誤則返回輸入信息涌庭,發(fā)生錯誤就返回表單提交頁面并顯示錯誤信息苦囱。
也許有人會說這種提交表單的方式過于笨重(在html模板中使用表單屬性),不夠靈活脾猛,有時候靈活和簡便是不可多得的,框架提供功能越多鱼鸠,可能導(dǎo)致其更為笨重猛拴,但是這里我們也可以不使用這種笨重的方式,我們只需要將html表單里屬性的name定義為和Form變量名一樣即可蚀狰,然后可以同樣在后臺創(chuàng)建接收輸入的表單愉昆,例如本例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>

后臺視圖函數(shù)不需要任何更改也可正常使用。
對于Form驗證Django為我們提供了一些通用的驗證機(jī)制麻蹋,如驗證屬性是否為空(required),長度驗證(max_length,min_length),甚至電話號碼email驗證(EmailField,PhoneField)跛溉。

Form自定義驗證

form驗證流程


這里寫圖片描述

1.函數(shù)full_clean()依次調(diào)用每個field的clean()函數(shù),該函數(shù)針對field的max_length扮授,unique等約束進(jìn)行驗證芳室,如果驗證成功則返回值,否則拋出ValidationError錯誤刹勃。如果有值返回堪侯,則放入form的cleaned_data字典中。
2.如果每個field的內(nèi)置clean()函數(shù)沒有拋出ValidationError錯誤荔仁,則調(diào)用以clean_開頭伍宦,以field名字結(jié)尾的自定義field驗證函數(shù)芽死。驗證成功和失敗的處理方式同步驟1。
3.最后次洼,調(diào)用form的clean()函數(shù)——注意关贵,這里是form的clean(),而不是field的clean()——如果clean沒有錯誤,那么它將返回cleaned_data字典卖毁。
4.如果到這一步?jīng)]有ValidationError拋出揖曾,那么cleaned_data字典就填滿了有效數(shù)據(jù)。否則cleaned_data不存在势篡,form的另外一個字典errors填上驗證錯誤翩肌。在template中,每個field獲取自己錯誤的方式是:{{ form.username.errors }}禁悠。
5.最后念祭,如果有錯誤is_valid()返回False,否則返回True碍侦。
對于某些自定義驗證規(guī)則我們可以通過重載上述clean_field函數(shù)或者clean函數(shù)來實現(xiàn)粱坤,例如對于用戶注冊需要驗證用戶名是否存在,兩次密碼輸入是否相等瓷产,我們可以通過以下代碼實現(xiàn)

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函數(shù)來判斷提交用戶名是否為‘cc’站玄,如果相等則驗證失敗并提示錯誤(通過 raise forms.ValidationError('username exsite!')來實現(xiàn)),然后重載clean函數(shù)來判斷兩次輸入密碼是否相同濒旦。

Form文件接收

在上述例子中雖然使用了ImageField株旷,但是并沒有演示如何在視圖函數(shù)中接收文件,對于文件來說我們同樣可以通過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()

和前一節(jié)的文件提交類似。


經(jīng)過本節(jié)梯嗽,我們了解了Form的基本使用--創(chuàng)建齿尽,渲染以及數(shù)據(jù)驗證,其實Form的功能遠(yuǎn)不止于此灯节,在后面我們會發(fā)現(xiàn)和Model結(jié)合Form具有更強(qiáng)大的功能循头,你只需要少量代碼即可完成大量功能,這就是Django這種集大成框架的優(yōu)勢(當(dāng)然會損失點靈活性)炎疆,甚至就是python的宗旨(life is short,you need python)卡骂,今天我們先了解到這里,謝謝大家支持磷雇。

參考鏈接

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

最近參加支付寶小程序比賽需要訪問量偿警,麻煩各位看官有空復(fù)制下面的話打開支付寶,搜索欄粘貼唯笙,在此多謝各位支持了

#JvCmawp74I1#長按復(fù)制此消息螟蒸,打開支付寶搜索盒使,體驗?zāi)暇┮咔榈貓D小程序
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市七嫌,隨后出現(xiàn)的幾起案子少办,更是在濱河造成了極大的恐慌,老刑警劉巖诵原,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件英妓,死亡現(xiàn)場離奇詭異,居然都是意外死亡绍赛,警方通過查閱死者的電腦和手機(jī)蔓纠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吗蚌,“玉大人腿倚,你說我怎么就攤上這事◎歉荆” “怎么了敷燎?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箩言。 經(jīng)常有香客問我硬贯,道長,這世上最難降的妖魔是什么陨收? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任饭豹,我火速辦了婚禮,結(jié)果婚禮上务漩,老公的妹妹穿的比我還像新娘墨状。我一直安慰自己,他們只是感情好菲饼,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著列赎,像睡著了一般宏悦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上包吝,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天饼煞,我揣著相機(jī)與錄音,去河邊找鬼诗越。 笑死砖瞧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嚷狞。 我是一名探鬼主播块促,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荣堰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了竭翠?” 一聲冷哼從身側(cè)響起振坚,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斋扰,沒想到半個月后渡八,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡传货,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年屎鳍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片问裕。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡逮壁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出僻澎,到底是詐尸還是另有隱情貌踏,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布窟勃,位于F島的核電站祖乳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秉氧。R本人自食惡果不足惜眷昆,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汁咏。 院中可真熱鬧亚斋,春花似錦、人聲如沸攘滩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漂问。三九已至赖瞒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚤假,已是汗流浹背栏饮。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留磷仰,地道東北人袍嬉。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像灶平,于是被迫代替她去往敵國和親伺通。 傳聞我的和親對象是個殘疾皇子箍土,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容