处理表单通常包含3步:
-
初始化GET(空白的后者预填充的表单)
-
POST非法数据(通常重新显示带有错误信息的表单)
-
POST合法数据(提交数据并重定向)
为了将你从这些烦人的重复步骤中解救出来,Django为表单提供了一类通用视图
基础表单
这是一个简单的联系表单:
|
1
2
3
4
5
6
7
8
9
10
|
# forms.pyfrom django import formsclass 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.pyfrom myapp.forms import ContactFormfrom django.views.generic.edit import FormViewclass 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.pyfrom django.core.urlresolvers import reversefrom django.db import modelsclass 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.pyfrom django.views.generic.edit import CreateView, UpdateView, DeleteViewfrom django.core.urlresolvers import reverse_lazyfrom myapp.models import Authorclass AuthorCreate(CreateView): model = Authorclass AuthorUpdate(UpdateView): model = Authorclass 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.pyfrom django.conf.urls import patterns, urlfrom myapp.views import AuthorCreate, AuthorUpdate, AuthorDeleteurlpatterns = 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.pyfrom django.contrib.auth import Userfrom django.db import modelsclass 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.pyfrom django import formsfrom myapp.models import Authorclass 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.pyfrom django.views.generic.edit import CreateViewfrom myapp.models import Authorfrom myapp.forms import AuthorFormclass 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 jsonfrom django.http import HttpResponsefrom django.views.generic.edit import CreateViewclass 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 responseclass AuthorCreate(AjaxableResponseMixin, CreateView): model = Author |
转载请注明出处