2009-07-18 36 views
7

在一個視圖處理的形式suggested模式似乎過於複雜和非幹了:替代django表單處理樣板?

def contact(request): 
    if request.method == 'POST': # If the form has been submitted... 
     form = ContactForm(request.POST) # A form bound to the POST data 
     if form.is_valid(): # All validation rules pass 
      # Process the data in form.cleaned_data 
      # ... 
      return HttpResponseRedirect('/thanks/') # Redirect after POST 
    else: 
     form = ContactForm() # An unbound form 

    return render_to_response('contact.html', { 
     'form': form, 
    }) 

這是一個很多條件句,它重複的ContactForm()施工,到處重複整個塊一個視圖需要處理一個表單。難道沒有更好的方法嗎?

+0

的Django從那以後幾年的通用視圖。這個問題和我看到的所有答案都過時了。請參閱:https://docs.djangoproject.com/en/1.9/ref/class-based-views/generic-editing/ – guettli 2016-01-29 20:36:59

回答

10

當然,您可以避免重複。大多數情況下,您需要傳入要使用的表單和模板名稱類的參數,在提交有效表單時處理已清理的數據,以及在處理後重定向的目標;另外,您需要一點額外的代碼來調用表單類一次,以生成綁定或未綁定的表單,並正確處理它。即:

def process_any_form(request, 
        form_class, template_file_name, 
        process_data_callable, redirect_destination): 

    form = form_class(request.POST if request.method == 'POST' else None) 

    if form.is_bound and form.is_valid(): 
     process_data_callable(form.cleaned_data) 
     return HttpResponseRedirect(redirect_destination) 

    return render_to_response(template_file_name, {'form': form}) 
+2

這工作。如果模板不僅僅需要「表單」,還需要擴展參數列表以包含值的散列。 – 2009-07-18 23:19:18

+0

S /散列/字典/,但是,是的,好主意:您可以在上下文中的半預填充字典d通過,並使用字典(d,形式=形式)作爲渲染的背景下,這使得解決方案更一般。 – 2009-07-18 23:58:43

2

處理表單樣板的方式混合了兩個問題:呈現表單來編輯和處理結果。您可以將其分解爲兩種方法,這些方法會以相同的render_to_response()調用的形式引入一些重複。當你重構它的時候,你的可能是最後的東西比上面的單一方法形式的可讀性差。

當我看樣板方法時,我沒有看到重複。 ContactForm()的兩種用法截然不同。這兩個條件似乎相當乾淨地顯示了處理表單所涉及的狀態轉換(呈現空白表單,接受提交直到有效,處理和重定向)。

0

可以編寫一個處理所有表單的條件的函數。你可以通過在函數傳遞特定於該表格後「is_valid」,如這樣做:

def FormHandler(request, CleaningFunction, redirecturl): 
    if request.method = 'POST': 
     if request.method == 'POST': # If the form has been submitted... 
      form = ContactForm(request.POST) # A form bound to the POST data 
      if form.is_valid(): # All validation rules pass 
       CleaningFunction(form) # Process the data in form.cleaned_data 
       return HttpResponseRedirect('/thanks/') # Redirect after POST 
    else: 
     form = ContactForm() # An unbound form 
    return form 

那麼你會從你的觀點稱FormHandler。請注意,這未經測試,可能有錯誤。

1

Alex的通用處理器打我,但FWIW我們走向一個泛型更低版本他的建議往往:

def contact(request): 
    post_data = request.POST if request.method == 'POST' else None 
    form = ContactForm(post_data) 
    if request.method == 'POST': 
     # perform normal validation checking, etc 

    return render_to_response('contact.html', { 
     'form': form, 
     }) 

如果post_data是無,那麼形式實例爲無界。否則,綁定處理將繼續正常進行。它避免了ContactForm的重複構造,但我同意Dave的答案,即重複構造不會因爲構造參數不同而影響我作爲重複項。

1

我對此非常厭煩,所以我寫了自己的通用視圖來處理它。在這個過程中,我發現django already has underdocumented generic views用於表單處理。它們與文檔通用視圖相當直接類似,但接受表單,基本上遵循您在示例中使用的相同模板。最終,我發現它們對於我的使用來說太不靈活和愚蠢(我不想要一個create_or_update視圖,我不想要分別對待這兩個動作。)

編輯:你不喜歡Fragsworth的答案,我談論的是同樣的事情,我想你也不會喜歡我的。這是一個如何工作的例子。

# in urls.py 
urlpatterns += patterns("", 
    (u'^...$', 'django.views.generic.create_update.update', { 
     'form_class': ContactForm }) 
) 

ContactForm必須有一個save()方法,和多數民衆贊成在您的表單處理邏輯去。

0

您可以繞過Django的形式模塊,只是做舊的方式方法,你沒有太多的損失恕我直言更多的靈活性。

最後一次我看到在Django表單是相當長一段時間以前,我不知道,如果事情發生了變化,但舉例來說,它並沒有真正讓你建立一個Ajax風格的形式;至少不容易。

6

你是對的也可能是更好的,這裏是一個更好的選擇(但請繼續閱讀):

def contact(request): 
    form = ContactForm(request.POST or None) # A form bound to the POST data 
    if form.is_valid(): # All validation rules pass 
     # Process the data in form.cleaned_data 
     # ... 
     return HttpResponseRedirect('/thanks/') # Redirect after POST 

    return render_to_response('contact.html', { 
     'form': form, 
    }) 

這個片段來自於從DjangoCon11稱爲Advanced Django Form Usage談話。

注意,這將處理一個空的形式有效(甚至在提交之前),如果所有字段都是可選的,您不使用CSRF保護。因此,要消除這種風險,你最好使用這一個:

def contact(request): 
    form = ContactForm(request.POST or None) # A form bound to the POST data 
    if request.method == 'POST' and form.is_valid(): # All validation rules pass 
     # Process the data in form.cleaned_data 
     # ... 
     return HttpResponseRedirect('/thanks/') # Redirect after POST 

    return render_to_response('contact.html', { 
     'form': form, 
    })