django是python語言快速實現web服務的大殺器,其開發效率能夠很是的高!但由於秉承了語言的靈活性,django框架又太靈活,以致於想實現任何功能都有種「條條大路通羅馬」的感受。這麼多種選擇放在一塊兒,如何分出高下?我想此時的場景下就兩個標準:一、相同的功能用最少的代碼實現(代碼少BUG也會少);二、相對最易於理解,從而易於維護和擴展。書歸正傳,web服務容許用戶輸入,基本上要靠表單。而django對錶單的支持力度很是大,咱們用不着在瀏覽器端的html文件裏寫大量<form>代碼,再到web端去匹配form裏的id/name/value、驗證規則,再與持久層數據庫比較並作操做。咱們須要完成的工做很是少,能夠沒有類似的重複代碼。有些複雜的場景,會要求一個表單的內容存放到多張表裏,本文將經過4個部分,闡述它的實現方法。html
一、django基礎表單的功能python
定義一個表單很是簡單,繼承類django.forms.Form便可,例如:web
這個表單類能夠生成HTML形式的form,能夠從request.POST中解析form到ProjectForm類實例。怎麼作到的呢?數據庫
看下django.forms.Form定義:django
註釋說得很清楚,Form這個類就是爲了實現declarative syntax的,也就是說,繼承了Form後,咱們直觀的表達ProjectForm裏要有一個Field名叫name,不關心其語法實現,而經過Form多繼承中的DeclarativeFieldsMetaclass語法糖,將會把name弄到類實例的self.fields裏。瀏覽器
咱們重點關注表單的BaseForm類,它實現了基本的邏輯。截選了一小段對接下來的陳述有意義的代碼,作一個簡單的註釋。併發
因此,基本表單的功能看BaseForm已經足夠了。框架
二、從模型建立表單post
django對於MVC中的C與M間的映射是很是體貼的,集中體現中Model模型中(好比模型的權限與用戶認證)。那麼,一個模型表明着RDS中的一張表,模型的實例表明着關係數據庫中的一行,而form如何與一行相對應呢?網站
定義一個模型引伸出的表單很是簡單,例如:
在model中告訴django模型是誰,在fields中告訴django須要在表單中建立哪些字段。django會有一個django.db.models.Field到django.forms.Field的轉換規則,此時會生成Form。咱們看看ModelForm是什麼樣的:
相似Form類,ModelFormMetaclass就是語法糖,咱們重點看BaseModelForm類:
因此,對於ModelForm咱們能夠傳入instance參數初始化表單,能夠調用save()方法直接將從html裏獲得的表單數據持久化到數據庫中。而咱們只須要幾十行代碼就能夠完成這麼多工做。
三、通用視圖
django.views.generic.ListView和django.views.generic.edit下的CreateView, UpdateView, DeleteView都是通用視圖。即,咱們又能夠經過它們,把不少重複的工做交給django完成,又能夠少寫不少代碼完成一樣的功能了。這裏僅以CreateView爲例說明,由於它相對最複雜,接下來的多ModelForm的提交也是在CreateView上進行的。
通用視圖使用時,只須要承繼後,再設置model或者form_class便可。好比CreateView就會由django自動的把頁面上POST出的form數據解析到model生成的表單(或者form_calss指定的ModelForm類型表單),同時調用表單的save方法將數據添加到模型對應的數據庫表中。固然GET請求時會生成空form到頁面上。能夠看到,除去定義model或者form類外,幾行代碼就能夠搞定這麼多事。咱們看看CreateView的繼承關係:
簡單介紹下CreateView通用視圖中每一個父類的做用。
因此,在用CreateView、一個模型、一個模板實現添加一行記錄的功能時是多麼簡單,由於這些父類會自動生成object,渲染到模板,解析form表單,save到數據庫中。因此,從模型建立出的表單ModelForm,配合上通用視圖後,威力巨大!!
四、多個ModelForm在一個form裏提交
終於能夠回到本文的主題了。CreateView默認是處理一個Model模型、一個ModelForm表單的,然而,不少時候爲了解耦,會把一張表拆成多張表,經過id關聯在一塊兒。在django的模型中就體現爲ForeignKey、ManyToManyField或者OneToOneField。而在業務邏輯上,須要體現爲一張表單,對應着數據庫裏的多張表。
例如,咱們但願錄入合同,其中合同Model中還有地址Model和項目Model,而項目Model中又有地址Model,等等。
固然,咱們有不少種實現的方案,可是,前面三部分說了那麼多,不是浪費口水的。咱們已經有了通用視圖+ModelForm這樣的利器,難道還須要手動去寫Form表單?咱們已經習慣了在Model裏定義好類型和有點註釋做用還能當label的verbose_name,還須要在forms.Form裏再來一遍?還須要在視圖中寫這麼通用的邏輯代碼嗎?固然不用。
inlineformset_factory是一種方案,但它限制太多,並且有些晦澀,我我的感受是不太好用的。
那麼,從第1部分我介紹的Form裏的prefix,以及第3部分裏類圖中的ProcessFormView容許重定義form_valid,以及第2部分中ModelForm的save方法的行爲控制,解決方案已經一目瞭然了。
拿上面提到的例子來講,咱們建立合同時,指明瞭項目,包括項目地址和合同簽定地址,這涉及到三張表和四條記錄(地址表有兩條)。
咱們三張表的模型以下:
接着,定義ModelForm表單,這很是簡單:
再寫視圖,這裏要重寫2個方法:
最後寫模板:
至此,咱們能夠只用幾十行代碼就完成複雜的功能,代碼邏輯也清晰可控。
從這篇文章裏也能夠看得出,django實在是快速開發網站的必備神器!固然,快速不表明不可以支撐大併發的應用,instagram這個很火的服務就是用django寫的。因爲python和django過於靈活,都將要求django的開發者們惟有更資深才能寫出生產環境下的服務。