在Django同1個頁面中的多表單處理詳解
快速上手Django實現(xiàn)項目
近期公司在做1個海淘的項目,APP為pylot。由于時間比較趕,加上隔壁那哥們不在,只能自己挑大梁了。結(jié)果,當項目做出來之后,被領(lǐng)導狠狠的批了一頓,說怎么用django寫,你能解決Django的內(nèi)存問題嗎,你能解決并發(fā)的問題嗎?Django那么重。
然后我只好回答說,正是因為它重,所以人家拿來寫大型項目。雖然這里不是為了上面這2個問題的,而是來說下如何快速開發(fā)原型的問題。
對于Django這樣基于模型的Web框架,實話說真的解決了很多繁瑣的工作。由于它1個模型對應(yīng)1張表,因此只要很短暫的時間就把原型給弄完了。實際上,我用Django主要是不用被頁面浪費我的時間,這樣我就可以專心寫API那方面了。
結(jié)果,公司這個項目除了自己可以看到外,還要實現(xiàn)1個B端的需求,而我此時的后臺功能已經(jīng)完成了,這可以如何是好。而區(qū)別在于只能讓注冊的用戶只能看到屬于它自己的訂單,而其他不變。
于是上官方文檔看了下表單的教程,看到1個ModelForm的玩意,通過它可以將后臺的表單直接渲染出來,而后在ModelForm類中通過instance關(guān)鍵字可以將對應(yīng)模型直接渲染出來,這樣花了1個星期的時間就把API、B端和公司的后臺完成了,效率還算比較高。
下面說下如何通過Django快速實現(xiàn)項目:
- 實際上分解問題很關(guān)鍵,把問題按等級劃分有助于加快開發(fā)速度
- 把不怎么會寫的代碼先跳過,使用繁瑣的方式先寫上去,后面再用其內(nèi)建的方式來替換
- 不要緊張,一定要保持淡定,不然你會發(fā)現(xiàn)你完全寫不出代碼
- 不要看官方文檔,因為寫的啰嗦又難找到重點
- 帶著問題在網(wǎng)上搜索答案,如果某個方式不行就換種思路去做,比如要實現(xiàn)1個多對多的關(guān)系的HTML組件,直接找第3方插件而不是看文檔實現(xiàn)
相信如何能做到以上幾點,才能把django的效率發(fā)揮出來。下面來看看本文的詳細介紹吧。
Django同1個頁面中的多表單處理
關(guān)于在同1個頁面多個表單提交的問題,實際上是項目中遇到的1個小問題。關(guān)于這個問題,主要有2個需要解決的問題:
- 多個表單的渲染問題
- 多個表單提交時外鍵的處理問題
下面我們分別進行說明。
當時在建模的時候使用了類似如下的方式:
from django.db import models class Store(models.Model): name = models.CharField('名稱', max_length=20) first = models.FloatField('首重') additional = models.FloatField('次重') img = models.ImageField('圖片', upload_to='store/1') class Depot(models.Model): s_name = models.ForeignKey(Store, verbose_name='倉庫') src = models.CharField('始發(fā)地', max_length=20) dest = models.CharField('目的地', max_length=20) days = models.PositiveSmallIntegerField('需要的天數(shù)') class Address(models.Model): s_name = models.ForeignKey(Store, verbose_name='倉庫') country = models.CharField('國家', max_length=20) state = models.CharField('省份', max_length=10) city = models.CharField('城市', max_length=10) description = models.TextField('描述', blank=True)
在這里,1個倉庫的數(shù)據(jù)主要由3個表組成,分別為它的一些基礎(chǔ)信息,可以配送的范圍、天數(shù)及其他一些附加信息組成。然后其頁面如下所示:
多表單渲染
而公司的需求就是我們要在商戶端上讓客戶在創(chuàng)建倉庫時填寫上述的內(nèi)容,由于我比較懶,而公司給出的時間也不是很充裕,于是直接使用ModelForm來實現(xiàn),而不需要一一的創(chuàng)建表單了。換句話說,我們要將多個模型表在同1個頁面中渲染出來,對于這樣的問題,主要有4種解決的方案:
- 在1個form組件中使用多個模型表單類
- 使用django提供的modelform_factory來解決
- 使用第3方插件django-betterforms或django-multipleformwizard這樣的插件
- 使用元類,然后繼承BaseForm進行表單的重寫。
這里我們使用第1種解決方案來實現(xiàn)多個表單渲染的問題。
這里我們在forms模塊下新建3個模型表單類:
from django.forms import ModelForm from models import Store, Address, Depot class StoreForm(ModelForm): class Meta: model = Store fields = '__all__' class AddressForm(ModelForm): class Meta: model = Address exclude = ['s_name'] class DepotForm(ModelForm): class Meta: model = Depot exclude = ['s_name']
然后在視圖中引入這3個表單:
from django.shortcuts import render_to_response, HttpResponseRedirect from django.template import RequestContext from forms import StoreForm, AddressForm, DepotForm def store_add(req): if req.method == 'POST': ... else: sf = StoreForm() af = AddressForm() df = DepotForm() return render_to_response('store_add.html', { 'sf': sf, 'af': af, 'df': df, }, context_instance=RequestContext(req))
默認情況下,我們先將對應(yīng)的表單渲染出來先。在這里我們往模板中輸出了多個變量,然后在模板中手動進行如下的處理:
<form action="" method='post' enctype='multipart/form-data'> {% csrf_token %} {{ sf.as_p }} {{ df.as_p }} {{ af.as_p }} <input type="submit" value = "添加" /> </form>
在這里,我們在1個表單中輸出多個表單,其頁面如下所示:
可以看到其效果與后臺的頁面相差不是很大,只是沒有對應(yīng)的樣式而已。
多表單提交外鍵處理
接著我們需要處理多個表單提交時的處理問題。
def store_add(req): if req.method == 'POST': sf = StoreForm(req.POST, req.FILES) af = AddressForm(req.POST) df = DepotForm(req.POST) if sf.is_valid() and af.is_valid() and df.is_valid(): sf.save() df.save() af.save() return HttpResponseRedirect('store') ...
在這里我們直接對這3個表單進行保存,結(jié)果出現(xiàn)了這樣1個錯誤。
NOT NULL constraint failed: app_depot.s_name_id
由于我們使用了1個外鍵進行了約束,而使用上述的方式會導致數(shù)據(jù)表中的s_name_id的字段數(shù)值為NULL,從而導致了錯誤。而上述的方式時直接就提交給數(shù)據(jù)庫了,導致后面的外鍵無法被滿足。
為了解決這個問題,我們采用延遲提交給數(shù)據(jù)庫的方式:
def store_add(req): if req.method == 'POST': ... if sf.is_valid() and af.is_valid() and df.is_valid(): form = sf.save(commit=False) sf.save() dform = df.save(commit=False) dform.s_name = form dform.save() aform = af.save(commit=False) aform.s_name = form aform.save() return HttpResponseRedirect('store') else: ...
在這里,我們先讓第1張表先不提交,將其保存為1個變量form中。而第2個張表也先不提交,我們將其實例的s_name修改為之前的第1張表返回的結(jié)果,然后再進行保存。這樣我們就實現(xiàn)了多張表的依賴導致的問題了。最后我們使用重定向的方式將成功添加后的頁面跳轉(zhuǎn)到該商戶的倉庫列表中。
其跳轉(zhuǎn)后的頁面如下所示:
這樣我們就解決了在1個頁面提交多個表單的問題。實際關(guān)于Django在1個頁面提交多個表單的問題,實際上問題不是很多,只要解決了渲染和提交時處理的問題,實際這個問題就迎刃而解了。重要的是如何拆分問題和解決問題的思路。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Python循環(huán)語句之while循環(huán)和for循環(huán)詳解
在Python中,循環(huán)語句用于重復執(zhí)行一段代碼,直到滿足某個條件為止,在Python中,有兩種主要的循環(huán)語句:for循環(huán)和while循環(huán),本文就來給大家介紹一下這兩個循環(huán)的用法,需要的朋友可以參考下2023-08-08Elasticsearches之python使用及Django與Flask集成示例
這篇文章主要為大家介紹了Elasticsearches之python使用及Django與Flask集成示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04selenium使用chrome瀏覽器測試(附chromedriver與chrome的對應(yīng)關(guān)系表)
這篇文章主要介紹了selenium使用chrome瀏覽器測試(附chromedriver與chrome的對應(yīng)關(guān)系表),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11python index() 與 rindex() 方法的使用示例詳解
這篇文章主要介紹了python index() 與 rindex() 方法的使用,需要的朋友可以參考下2022-12-12Python執(zhí)行時間計算方法以及優(yōu)化總結(jié)
python腳本運行時間遠遠大于python腳本中統(tǒng)計的計算時間,所以本文將為大家分享就幾個Python執(zhí)行時間計算方法以及優(yōu)化,感興趣的可以了解一下2022-08-08