表单的处理通常有3条分支:
你自己实现这些功能经常导致许多重复的样本代码(参见Using a form in a view)。 为了避免这点,Django 提供一系列的通用的基于类的视图用于表单的处理。
根据一个简单的联系人表单:
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
来构造其视图:
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)
注:
TemplateResponseMixin
所以这里可以使用template_name
。form_valid()
的默认实现只是简单地重定向到success_url
。通用视图在与模型一起工作时会真正光芒四射。 这些通用的视图将自动创建一个ModelForm
,只要它们能知道使用哪一个模型类:
model
属性,则使用该模型类。get_object()
返回一个对象,则使用该对象的类。queryset
,则使用该查询集的模型。模型表单提供一个form_valid()
的实现,它自动保存模型。 如果您有任何特殊要求,您可以覆盖此;见下面的例子。
你甚至不需要为CreateView
和UpdateView
提供success_url
—— 如果模型对象的get_absolute_url()
存在的话,它们将使用get_absolute_url()。
如果你想使用一个自定义的ModelForm
(例如添加额外的验证),只需简单地在你的视图上设置form_class
。
注
当指定一个自定义的表单类时,你必须指定模型,即使form_class
可能是一个ModelForm
。
首先我们需要添加get_absolute_url()
到我们的Author
类中:
from django.urls 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
及其伙伴来做实际的工作。 请注意,我们在这里只是配置基于类的通用视图;我们不必自己写任何逻辑:
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls 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()
。
fields
属性的工作方式与ModelForm
的内部Meta
类的fields
属性相同。 除非你用另外一种方式定义表单类,该属性是必须的,如果没有将引发一个ImproperlyConfigured
异常。
如果你同时指定fields
和form_class
属性,将引发一个ImproperlyConfigured
异常。
最后,我们来将这些新的视图放到URLconf 中:
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
并基于模型来构造template_name
。
在这个例子中:
CreateView
和UpdateView
使用 myapp/author_form.html
DeleteView
使用 myapp/author_confirm_delete.html
如果你希望分开CreateView
和UpdateView
的模板,你可以设置你的视图类的template_name
或template_name_suffix
。
request.user
¶使用CreateView时,为了得到创建该对象的用户,你可以使用一个自定义的ModelForm 来实现这点。 首先,向模型添加外键关联:
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, on_delete=models.CASCADE)
# ...
在这个视图中,请确保你没有将created_by
包含进要编辑的字段列表,并覆盖form_valid()
来添加这个用户:
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()
来decorate this
view,或者在form_valid()
中处理未认证的用户。
下面是一个简单的实例,展示你可以如何实现一个表单,使它可以同时为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']
2017年9月6日