处理表单通常包含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
|
转载请注明出处