表單的處理通常有3 個步驟:
你自己實現(xiàn)這些功能經(jīng)常導致許多重復的樣本代碼(參見在視圖中使用表單)。為了避免這點,Django 提供一系列的通用的基于類的視圖用于表單的處理。
根據(jù)一個簡單的聯(lián)系人表單:
#forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
可以使用FormView來構(gòu)造其視圖:
#views.py
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super(ContactView, self).form_valid(form)
注:
FormView繼承TemplateResponseMixin所以這里可以使用template_name。form_valid()的默認實現(xiàn)只是簡單地重定向到success_url。通用視圖在于模型一起工作時會真正光芒四射。這些通用的視圖將自動創(chuàng)建一個ModelForm,只要它們能知道使用哪一個模型類:
model屬性,則使用該模型類。get_object() 返回一個對象,則使用該對象的類。queryset,則使用該查詢集的模型。模型表單提供一個form_valid() 的實現(xiàn),它自動保存模型。如果你有特殊的需求,可以覆蓋它;參見下面的例子。
你甚至不需要為CreateView 和UpdateView提供success_url —— 如果存在它們將使用模型對象的get_absolute_url()。
如果你想使用一個自定義的ModelForm(例如添加額外的驗證),只需簡單地在你的視圖上設置form_class。
注
當指定一個自定義的表單類時,你必須指定模型,即使
form_class可能是一個ModelForm。
首先我們需要添加get_absolute_url() 到我們的Author 類中:
#models.py
from django.core.urlresolvers import reverse
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
return reverse('author-detail', kwargs={'pk': self.pk})
然后我們可以使用CreateView 機器伙伴來做實際的工作。注意這里我們是如何配置通用的基于類的視圖的;我們自己沒有寫任何邏輯:
#views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
注
這里我們必須使用
reverse_lazy()而不是reverse,因為在該文件導入時URL 還沒有加載。
fields 屬性的工作方式與ModelForm 的內(nèi)部Meta類的fields 屬性相同。除非你用另外一種方式定義表單類,該屬性是必須的,如果沒有將引發(fā)一個ImproperlyConfigured 異常。
如果你同時指定fields 和form_class 屬性,將引發(fā)一個ImproperlyConfigured 異常。
Changed in Django 1.8:
省略fields 屬性在以前是允許的,但是導致表單帶有模型的所有字段。
Changed in Django 1.8:
以前,如果fields 和form_class 兩個都指定,會默默地忽略 fields。
最后,我我們來將這些新的視圖放到URLconf 中:
#urls.py
from django.conf.urls import url
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete
urlpatterns = [
# ...
url(r'author/add/$', AuthorCreate.as_view(), name='author_add'),
url(r'author/(?P<pk>[0-9]+)/$', AuthorUpdate.as_view(), name='author_update'),
url(r'author/(?P<pk>[0-9]+)/delete/$', AuthorDelete.as_view(), name='author_delete'),
]
注
這些表單繼承
SingleObjectTemplateResponseMixin,它使用template_name_suffix并基于模型來構(gòu)造template_name。在這個例子中:
CreateView和UpdateView使用myapp/author_form.htmlDeleteView使用myapp/author_confirm_delete.html如果你希望分開
CreateView和UpdateView的模板,你可以設置你的視圖類的template_name或template_name_suffix。
為了跟蹤使用CreateView 創(chuàng)建一個對象的用戶,你可以使用一個自定義的ModelForm 來實現(xiàn)這點。首先,向模型添加外鍵關聯(lián):
#models.py
from django.contrib.auth.models import User
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
created_by = models.ForeignKey(User)
# ...
在這個視圖中,請確保你沒有將created_by 包含進要編輯的字段列表,并覆蓋form_valid() 來添加這個用戶:
#views.py
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(AuthorCreate, self).form_valid(form)
注意,你需要使用login_required() 來裝飾這個視圖,或者在form_valid() 中處理未認證的用戶。
下面是一個簡單的實例,展示你可以如何實現(xiàn)一個表單,使它可以同時為AJAX 請求和‘普通的’表單POST 工作:
from django.http import JsonResponse
from django.views.generic.edit import CreateView
from myapp.models import Author
class AjaxableResponseMixin(object):
"""
Mixin to add AJAX support to a form.
Must be used with an object-based FormView (e.g. CreateView)
"""
def form_invalid(self, form):
response = super(AjaxableResponseMixin, self).form_invalid(form)
if self.request.is_ajax():
return JsonResponse(form.errors, status=400)
else:
return response
def form_valid(self, form):
# We make sure to call the parent's form_valid() method because
# it might do some processing (in the case of CreateView, it will
# call form.save() for example).
response = super(AjaxableResponseMixin, self).form_valid(form)
if self.request.is_ajax():
data = {
'pk': self.object.pk,
}
return JsonResponse(data)
else:
return response
class AuthorCreate(AjaxableResponseMixin, CreateView):
model = Author
fields = ['name']
譯者:Django 文檔協(xié)作翻譯小組,原文:Built-in editing views。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。