用基于类的通用视图处理表单(Class-based generic views)
处理表单通常包含3步:
-
初始化GET(空白的后者预填充的表单)
-
POST非法数据(通常重新显示带有错误信息的表单)
-
POST合法数据(提交数据并重定向)
为了将你从这些烦人的重复步骤中解救出来,Django为表单提供了一类通用视图
基础表单
这是一个简单的联系表单:
1
2
3
4
5
6
7
8
9
10
|
# 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来构造:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 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()只是简单的重定向到success_url
模型表单
在处理模型的时候,通用视图才能大显身手。只要可以找到要处理的模型类,这些通用视图会自动创建ModelForm:
-
如果指明了model属性,那个模型类将被选择
-
如果get_object()返回了一个对象,那个对象的类将会被选择
-
如果指明了queryset,相关的模型将会被选择
模型表单视图提供form_valid()方法来自动保存模型。如果有特殊需要,你可以重写它,看下面的例子
你甚至不必为CreateView和UpdateView指明success_url,他们会自动选择模型对象中的get_absolute_url()(如果存在的话)。你也可以简单地设置form_class来定制一个ModelForm(为模型添加额外的验证)
注意当指定一个定制的表单类时,你也必须指定模型,尽管form_class可能就是一个ModelForm
首先我们需要添加为Author类添加get_absolute_url()
1
2
3
4
5
6
7
8
9
|
# 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和它的朋友们来做实际的工作。注意我们在这里如何匹配基于类的通用视图,我们不必写任何的逻辑代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 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 class AuthorUpdate(UpdateView): model = Author class AuthorDelete(DeleteView): model = Author success_url = reverse_lazy( 'author-list' ) |
注意:这里必须要用reverse_lazy(),而不仅仅是reverse,因为当文件被导入时urls没有被加载
最后,我们在URLconf中加上这些新的视图:
1
2
3
4
5
6
7
8
9
10
|
# urls.py from django.conf.urls import patterns, url from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete urlpatterns = patterns('', # ... url(r 'author/add/$' , AuthorCreate.as_view(), name = 'author_add' ), url(r 'author/(?P<pk>\d+)/$' , AuthorUpdate.as_view(), name = 'author_update' ), url(r 'author/(?P<pk>\d+)/delete/$' , AuthorDelete.as_view(), name = 'author_delete' ), ) |
注意:这些视图都继承于SingleObjectTemplateMinxin,这个类使用template_name_suffix来构造基于模型的template_name
在这个例子中:
-
CreateView和UpdateView使用myapp/author_form.html
-
DeleteView使用myapp/author_confirm_date.html
如果你想要为CreateView和UpdateView使用不同的模板,你可以在你的视图类里设置template_name或者template_name_suffix
模型和request.user
为了跟踪用户使用CreateView创建对象,你可以使用定制的ModelForm来实现它。
首先,为模型增加外键:
1
2
3
4
5
6
7
8
9
|
# models.py from django.contrib.auth import User from django.db import models class Author(models.Model): name = models.CharField(max_length = 200 ) created_by = models.ForeignKey(User) # ... |
创建一个定制的ModelForm来隔离created_by,以免用户去编辑它:
1
2
3
4
5
6
7
8
|
# forms.py from django import forms from myapp.models import Author class AuthorForm(forms.ModelForm): class Meta: model = Author exclude = ( 'created_by' ,) |
在这个视图中,使用定制的form_class并重写form_valid()来增加user:
1
2
3
4
5
6
7
8
9
10
11
12
|
# views.py from django.views.generic.edit import CreateView from myapp.models import Author from myapp.forms import AuthorForm class AuthorCreate(CreateView): form_class = AuthorForm model = Author def form_valid( self , form): form.instance.created_by = self .request.user return super (AuthorCreate, self ).form_valid(form) |
注意你需要使用login_required()来装饰这个视图,或者在form_valid()里处理未登录的用户
AJAX例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import json from django.http import HttpResponse from django.views.generic.edit import CreateView class AjaxableResponseMixin( object ): """ Mixin to add AJAX support to a form. Must be used with an object-based FormView (e.g. CreateView) """ def render_to_json_response( self , context, * * response_kwargs): data = json.dumps(context) response_kwargs[ 'content_type' ] = 'application/json' return HttpResponse(data, * * response_kwargs) def form_invalid( self , form): response = super (AjaxableResponseMixin, self ).form_invalid(form) if self .request.is_ajax(): return self .render_to_json_response(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 self .render_to_json_response(data) else : return response class AuthorCreate(AjaxableResponseMixin, CreateView): model = Author |
转载请注明出处