Django中同一頁面中的多表單處理

原文地址:html

http://52sox.com/how-to-handl...數據庫

關於在同1個頁面多個表單提交的問題,其實是項目中遇到的1個小問題。關於這個問題,主要有2個須要解決的問題:django

  • 多個表單的渲染問題app

  • 多個表單提交時外鍵的處理問題post

下面咱們分別進行說明。
當時在建模的時候使用了相似以下的方式:spa

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('始發地', max_length=20)
    dest = models.CharField('目的地', max_length=20)
    days = models.PositiveSmallIntegerField('須要的天數')

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個倉庫的數據主要由3個表組成,分別爲它的一些基礎信息,能夠配送的範圍、天數及其餘一些附加信息組成。而後其頁面以下所示:插件

1.jpg

多表單渲染

而公司的需求就是咱們要在商戶端上讓客戶在建立倉庫時填寫上述的內容,因爲我比較懶,而公司給出的時間也不是很充裕,因而直接使用ModelForm來實現,而不須要一一的建立表單了。換句話說,咱們要將多個模型表在同1個頁面中渲染出來,對於這樣的問題,主要有4種解決的方案:code

  • 在1個form組件中使用多個模型表單類orm

  • 使用django提供的modelform_factory來解決csrf

  • 使用第3方插件django-betterformsdjango-multipleformwizard這樣的插件

  • 使用元類,而後繼承BaseForm進行表單的重寫。

這裏咱們使用第1種解決方案來實現多個表單渲染的問題。
這裏咱們在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))

默認狀況下,咱們先將對應的表單渲染出來先。在這裏咱們往模板中輸出了多個變量,而後在模板中手動進行以下的處理:

<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個表單中輸出多個表單,其頁面以下所示:

2.jpg

能夠看到其效果與後臺的頁面相差不是很大,只是沒有對應的樣式而已。

多表單提交外鍵處理

接着咱們須要處理多個表單提交時的處理問題。

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個表單進行保存,結果出現了這樣1個錯誤。

NOT NULL constraint failed: app_depot.s_name_id

因爲咱們使用了1個外鍵進行了約束,而使用上述的方式會致使數據表中的s_name_id的字段數值爲NULL,從而致使了錯誤。而上述的方式時直接就提交給數據庫了,致使後面的外鍵沒法被知足。爲了解決這個問題,咱們採用延遲提交給數據庫的方式:

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張表返回的結果,而後再進行保存。這樣咱們就實現了多張表的依賴致使的問題了。最後咱們使用重定向的方式將成功添加後的頁面跳轉到該商戶的倉庫列表中。
其跳轉後的頁面以下所示:

3.jpg

這樣咱們就解決了在1個頁面提交多個表單的問題。
實際關於Django在1個頁面提交多個表單的問題,實際上問題不是不少,只要解決了渲染和提交時處理的問題,實際這個問題就迎刃而解了。重要的是如何拆分問題和解決問題的思路。

參考文章:

http://stackoverflow.com/ques...

相關文章
相關標籤/搜索