表單的處理通常有3 個(gè)步驟:
你自己實(shí)現(xiàn)這些功能經(jīng)常導(dǎo)致許多重復(fù)的樣本代碼(參見在視圖中使用表單)。為了避免這點(diǎn),Django 提供一系列的通用的基于類的視圖用于表單的處理。
根據(jù)一個(gè)簡(jiǎn)單的聯(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()的默認(rèn)實(shí)現(xiàn)只是簡(jiǎn)單地重定向到success_url。通用視圖在于模型一起工作時(shí)會(huì)真正光芒四射。這些通用的視圖將自動(dòng)創(chuàng)建一個(gè)ModelForm,只要它們能知道使用哪一個(gè)模型類:
model屬性,則使用該模型類。get_object() 返回一個(gè)對(duì)象,則使用該對(duì)象的類。queryset,則使用該查詢集的模型。模型表單提供一個(gè)form_valid() 的實(shí)現(xiàn),它自動(dòng)保存模型。如果你有特殊的需求,可以覆蓋它;參見下面的例子。
你甚至不需要為CreateView 和UpdateView提供success_url —— 如果存在它們將使用模型對(duì)象的get_absolute_url()。
如果你想使用一個(gè)自定義的ModelForm(例如添加額外的驗(yàn)證),只需簡(jiǎn)單地在你的視圖上設(shè)置form_class。
注
當(dāng)指定一個(gè)自定義的表單類時(shí),你必須指定模型,即使
form_class可能是一個(gè)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 機(jī)器伙伴來做實(shí)際的工作。注意這里我們是如何配置通用的基于類的視圖的;我們自己沒有寫任何邏輯:
#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,因?yàn)樵谠撐募?dǎo)入時(shí)URL 還沒有加載。
fields 屬性的工作方式與ModelForm 的內(nèi)部Meta類的fields 屬性相同。除非你用另外一種方式定義表單類,該屬性是必須的,如果沒有將引發(fā)一個(gè)ImproperlyConfigured 異常。
如果你同時(shí)指定fields 和form_class 屬性,將引發(fā)一個(gè)ImproperlyConfigured 異常。
Changed in Django 1.8:
省略fields 屬性在以前是允許的,但是導(dǎo)致表單帶有模型的所有字段。
Changed in Django 1.8:
以前,如果fields 和form_class 兩個(gè)都指定,會(huì)默默地忽略 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。在這個(gè)例子中:
CreateView和UpdateView使用myapp/author_form.htmlDeleteView使用myapp/author_confirm_delete.html如果你希望分開
CreateView和UpdateView的模板,你可以設(shè)置你的視圖類的template_name或template_name_suffix。
為了跟蹤使用CreateView 創(chuàng)建一個(gè)對(duì)象的用戶,你可以使用一個(gè)自定義的ModelForm 來實(shí)現(xiàn)這點(diǎn)。首先,向模型添加外鍵關(guā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)
# ...
在這個(gè)視圖中,請(qǐng)確保你沒有將created_by 包含進(jìn)要編輯的字段列表,并覆蓋form_valid() 來添加這個(gè)用戶:
#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() 來裝飾這個(gè)視圖,或者在form_valid() 中處理未認(rèn)證的用戶。
下面是一個(gè)簡(jiǎn)單的實(shí)例,展示你可以如何實(shí)現(xiàn)一個(gè)表單,使它可以同時(shí)為AJAX 請(qǐng)求和‘普通的’表單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)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。