form = ProductForm(request.POST or None):python or 含义:如果第1个为真,返回第1个,否则返回第2个
def search(request):
**errors = []**
if 'q' in request.GET:
q = request.GET['q']
if not q:
**errors.append('Enter a search term.')**
elif len(q) > 20:
**errors.append('Please enter at most 20 characters.'
else:
books = Book.objects.filter(title__icontains=q)
return render_to_response('search_results.html',
{'books': books, 'query': q})
return render_to_response('search_form.html',
{**'errors': errors** })
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
def contact(request):
errors = []
if request.method == 'POST':
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '@' not in request.POST['email']:
errors.append('Enter a valid e‐mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply@example.com'),
['siteowner@example.com'],
)
return HttpResponseRedirect('/contact/thanks/')
return render_to_response('contact_form.html',
{'errors': errors})
当邮件发送成功之后,我们使用HttpResponseRedirect对象将网页重定向至一个包含成功信息的页面。 包
含成功信息的页面这里留给读者去编写(很简单 一个视图/URL映射/一份模板即可),但是我们要解释一
下为何重定向至新的页面,而不是在模板中直接调用render_to_response()来输出。
原因就是: 若用户刷新一个包含POST表单的页面,那么请求将会重新发送造成重复。 这通常会造成非期望
的结果,比如说重复的数据库记录;在我们的例子中,将导致发送两封同样的邮件。 如果用户在POST表单
之后被重定向至另外的页面,就不会造成重复的请求了。
我们应每次都给成功的POST请求做重定向。 这就是web开发的最佳实践。
1)Python解释器里面看看这个类做了些什么。 它做的第一件事是将自己显示成HTML:
>>> from contact.forms import ContactForm
>>> f = ContactForm()
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" id="id_
<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email"
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_
Form对象做的第二件事是校验数据。 为了校验数据,我们创建一个新的对Form象,并且传入一个与定义匹配的
字典类型数据:
>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})
一旦你对一个Form实体赋值,你就得到了一个绑定form:
>>> f.is_bound
obook.py3k.cn/2.0/chapter07/12/182010-5-5第七章:表单
True
调用任何绑定form的is_valid()方法,就可以知道它的数据是否合法。 我们已经为每个字段传入了值,因此整
个Form是合法的:
>>> f.is_valid()
True
每一个邦定Form实体都有一个errors属性,它为你提供了一个字段与错误消息相映射的字典表。
>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.errors
{'message': [u'This field is required.']}
最终,如果一个Form实体的数据是合法的,它就会有一个可用的cleaned_data属性。 这是一个包含干净的提交
数据的字典。 Django的form框架不但校验数据,它还会把它们转换成相应的Python类型数据,这叫做清理数
据。
>>> f = ContactForm({subject': Hello, email: adrian@example.com, message: Nice site!})
>>> f.is_valid()
True
>>> f.cleaned_data
{message': uNice site!, email: uadrian@example.com, subject: uHello}
在视图中使用Form对象
from django.shortcuts import render_to_response
from mysite.contact.forms import ContactForm
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', 'noreply@example.com'),
['siteowner@example.com'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render_to_response('contact_form.html', {'form': form})
# contact_form.html
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
看看,我们能移除这么多不整齐的代码! Django的forms框架处理HTML显示、数据校验、数据清理和表单错
误重现。
1 改变字段显示
你可能首先注意到:当你在本地显示这个表单的时,message字段被显示成`` input type=”text”`` ,而它应该
被显示成<`` textarea`` >。我们可以通过设置* widget* 来修改它:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField(**widget=forms.Textarea** )
obook.py3k.cn/2.0/chapter07/14/182010-5-5第七章:表单
forms框架把每一个字段的显示逻辑分离到一组部件(widget)中。 每一个字段类型都拥有一个默认的部件,
我们也可以容易地替换掉默认的部件,或者提供一个自定义的部件。
考虑一下Field类表现* 校验逻辑* ,而部件表现* 显示逻辑* 。
2 设置最大长度
一个最经常使用的校验要求是检查字段长度。 另外,我们应该改进ContactForm,使subject限制在100个字符
以内。 为此,仅需为CharField提供max_length参数,像这样:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(**max_length=100** )
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
选项min_length参数同样可用。
3 设置初始值
让我们再改进一下这个表单:为字subject段添加* 初始值* : "I love your site!" (一点建议,但没坏处。
)为此,我们可以在创建Form实体时,使用initial参数:
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', `'noreply@example.com`_'),
[`'siteowner@example.com`_'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm(
**initial={'subject': 'I love your site!'}**
)
return render_to_response('contact_form.html', {'form': form})
现在,subject字段将被那个句子填充。
请注意,传入* 初始值* 数据和传入数据以* 绑定* 表单是有区别的。 最大的区别是,如果仅传入* 初始值* 数
据,表单是unbound的,那意味着它没有错误消息。
4 自定义校验规则
假设我们已经发布了反馈页面了,email已经开始源源不断地涌入了。 这里有一个问题: 一些提交的消息只有
一两个字,我们无法得知详细的信息。 所以我们决定增加一条新的校验: 来点专业精神,最起码写四个字,拜
托。
我们有很多的方法把我们的自定义校验挂在Django的form上。 如果我们的规则会被一次又一次的使用,我们
可以创建一个自定义的字段类型。 大多数的自定义校验都是一次性的,可以直接绑定到form类.
djangobook.py3k.cn/2.0/chapter07/15/182010-5-5第七章:表单
我们希望`` message`` 字段有一个额外的校验,我们增加一个`` clean_message()`` 方法到`` Form`` 类:
1from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Django的form系统自动寻找匹配的函数方法,该方法名称以clean_开头,并以字段名称结束。 如果有这样
方法,它将在校验时被调用。
特别地,clean_message()方法将在指定字段的默认校验逻辑执行* 之后* 被调用。(本例中,在必
填CharField这个校验逻辑之后。)因为字段数据已经被部分处理,所以它被从self.cleaned_data中提取出来
了。同样,我们不必担心数据是否为空,因为它已经被校验过了。
我们简单地使用了len()和split()的组合来计算单词的数量。 如果用户输入字数不足,我们抛出一
个forms.ValidationError型异常。这个异常的描述会被作为错误列表中的一项显示给用户。
在函数的末尾显式地返回字段的值非常重要。 我们可以在我们自定义的校验方法中修改它的值(或者把它转换
成另一种Python类型)。 如果我们忘记了这一步,None值就会返回,原始的数据就丢失掉了。
5 指定标签
HTML表单中自动生成的标签默认是按照规则生成的:用空格代替下划线,首字母大写。如email的标签
是"Email" 。(好像在哪听到过? 是的,同样的逻辑被用于模块(model)中字段的verbose_name值。 我们在
第五章谈到过。)
像在模块中做过的那样,我们同样可以自定义字段的标签。 仅需使用label,像这样:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False, **label='Your e‐mail address'** )
message = forms.CharField(widget=forms.Textarea)
6 定制Form设计
在上面的`` contact_form.html`` 模板中我们使用`` {{form.as_table}}`` 显示表单,不过我们可以使用其他更精
确控制表单显示的方法。
修改form的显示的最快捷的方式是使用CSS。 尤其是错误列表,可以增强视觉效果。自动生成的错误列表精确
的使用`` <ul class=”errorlist”>``,这样,我们就可以针对它们使用CSS。 下面的CSS让错误更加醒目了:
<style type="text/css">
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background‐color: red;
display: block;
font‐size: 10px;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
虽然,自动生成HTML是很方便的,但是在某些时候,你会想覆盖默认的显示。 {{form.as_table}}和其它的方
法在开发的时候是一个快捷的方式,form的显示方式也可以在form中被方便地重写。
每一个字段部件(<input type=”text”>, <select>, <textarea>, 或者类似)都可以通过访问{{form.字段名}}进
行单独的渲染。
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<div class="field">
{{ form.subject.errors }}
<label for="id_subject">Subject:</label>
{{ form.subject }}
</div>
<div class="field">
{{ form.email.errors }}
<label for="id_email">Your e‐mail address:</label>
{{ form.email }}
</div>
<div class="field">
{{ form.message.errors }}
<label for="id_message">Message:</label>
{{ form.message }}
</div>
<input type="submit" value="Submit">
</form>
</body>
</html>
{{ form.message.errors }} 会在 <ul class="errorlist"> 里面显示,如果字段是合法的,或者form没有被绑
定,就显示一个空字符串。 我们还可以把 form.message.errors 当作一个布尔值或者当它是list在上面做迭代,
例如:
<div class="field{% if form.message.errors %} errors{% endif %}">
{% if form.message.errors %}
<ul>
{% for error in form.message.errors %}
<li><strong>{{ error }}</strong></li>
{% endfor %}
</ul>
{% endif %}
<label for="id_message">Message:</label>
Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by
Chinese translate hosting by py3k.cn.
Document License`_.
{{ form.message }}
</div>
在校验失败的情况下, 这段代码会在包含错误字段的div的class属性中增加一个”errors”,在一个有序列表中
显示错误信息。
def search(request):
**errors = []**
if 'q' in request.GET:
q = request.GET['q']
if not q:
**errors.append('Enter a search term.')**
elif len(q) > 20:
**errors.append('Please enter at most 20 characters.'
else:
books = Book.objects.filter(title__icontains=q)
return render_to_response('search_results.html',
{'books': books, 'query': q})
return render_to_response('search_form.html',
{**'errors': errors** })
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
def contact(request):
errors = []
if request.method == 'POST':
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '@' not in request.POST['email']:
errors.append('Enter a valid e‐mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply@example.com'),
['siteowner@example.com'],
)
return HttpResponseRedirect('/contact/thanks/')
return render_to_response('contact_form.html',
{'errors': errors})
当邮件发送成功之后,我们使用HttpResponseRedirect对象将网页重定向至一个包含成功信息的页面。 包
含成功信息的页面这里留给读者去编写(很简单 一个视图/URL映射/一份模板即可),但是我们要解释一
下为何重定向至新的页面,而不是在模板中直接调用render_to_response()来输出。
原因就是: 若用户刷新一个包含POST表单的页面,那么请求将会重新发送造成重复。 这通常会造成非期望
的结果,比如说重复的数据库记录;在我们的例子中,将导致发送两封同样的邮件。 如果用户在POST表单
之后被重定向至另外的页面,就不会造成重复的请求了。
我们应每次都给成功的POST请求做重定向。 这就是web开发的最佳实践。
1)Python解释器里面看看这个类做了些什么。 它做的第一件事是将自己显示成HTML:
>>> from contact.forms import ContactForm
>>> f = ContactForm()
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" id="id_
<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email"
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_
Form对象做的第二件事是校验数据。 为了校验数据,我们创建一个新的对Form象,并且传入一个与定义匹配的
字典类型数据:
>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})
一旦你对一个Form实体赋值,你就得到了一个绑定form:
>>> f.is_bound
obook.py3k.cn/2.0/chapter07/12/182010-5-5第七章:表单
True
调用任何绑定form的is_valid()方法,就可以知道它的数据是否合法。 我们已经为每个字段传入了值,因此整
个Form是合法的:
>>> f.is_valid()
True
每一个邦定Form实体都有一个errors属性,它为你提供了一个字段与错误消息相映射的字典表。
>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.errors
{'message': [u'This field is required.']}
最终,如果一个Form实体的数据是合法的,它就会有一个可用的cleaned_data属性。 这是一个包含干净的提交
数据的字典。 Django的form框架不但校验数据,它还会把它们转换成相应的Python类型数据,这叫做清理数
据。
>>> f = ContactForm({subject': Hello, email: adrian@example.com, message: Nice site!})
>>> f.is_valid()
True
>>> f.cleaned_data
{message': uNice site!, email: uadrian@example.com, subject: uHello}
在视图中使用Form对象
from django.shortcuts import render_to_response
from mysite.contact.forms import ContactForm
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', 'noreply@example.com'),
['siteowner@example.com'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render_to_response('contact_form.html', {'form': form})
# contact_form.html
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
看看,我们能移除这么多不整齐的代码! Django的forms框架处理HTML显示、数据校验、数据清理和表单错
误重现。
1 改变字段显示
你可能首先注意到:当你在本地显示这个表单的时,message字段被显示成`` input type=”text”`` ,而它应该
被显示成<`` textarea`` >。我们可以通过设置* widget* 来修改它:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField(**widget=forms.Textarea** )
obook.py3k.cn/2.0/chapter07/14/182010-5-5第七章:表单
forms框架把每一个字段的显示逻辑分离到一组部件(widget)中。 每一个字段类型都拥有一个默认的部件,
我们也可以容易地替换掉默认的部件,或者提供一个自定义的部件。
考虑一下Field类表现* 校验逻辑* ,而部件表现* 显示逻辑* 。
2 设置最大长度
一个最经常使用的校验要求是检查字段长度。 另外,我们应该改进ContactForm,使subject限制在100个字符
以内。 为此,仅需为CharField提供max_length参数,像这样:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(**max_length=100** )
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
选项min_length参数同样可用。
3 设置初始值
让我们再改进一下这个表单:为字subject段添加* 初始值* : "I love your site!" (一点建议,但没坏处。
)为此,我们可以在创建Form实体时,使用initial参数:
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', `'noreply@example.com`_'),
[`'siteowner@example.com`_'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm(
**initial={'subject': 'I love your site!'}**
)
return render_to_response('contact_form.html', {'form': form})
现在,subject字段将被那个句子填充。
请注意,传入* 初始值* 数据和传入数据以* 绑定* 表单是有区别的。 最大的区别是,如果仅传入* 初始值* 数
据,表单是unbound的,那意味着它没有错误消息。
4 自定义校验规则
假设我们已经发布了反馈页面了,email已经开始源源不断地涌入了。 这里有一个问题: 一些提交的消息只有
一两个字,我们无法得知详细的信息。 所以我们决定增加一条新的校验: 来点专业精神,最起码写四个字,拜
托。
我们有很多的方法把我们的自定义校验挂在Django的form上。 如果我们的规则会被一次又一次的使用,我们
可以创建一个自定义的字段类型。 大多数的自定义校验都是一次性的,可以直接绑定到form类.
djangobook.py3k.cn/2.0/chapter07/15/182010-5-5第七章:表单
我们希望`` message`` 字段有一个额外的校验,我们增加一个`` clean_message()`` 方法到`` Form`` 类:
1from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Django的form系统自动寻找匹配的函数方法,该方法名称以clean_开头,并以字段名称结束。 如果有这样
方法,它将在校验时被调用。
特别地,clean_message()方法将在指定字段的默认校验逻辑执行* 之后* 被调用。(本例中,在必
填CharField这个校验逻辑之后。)因为字段数据已经被部分处理,所以它被从self.cleaned_data中提取出来
了。同样,我们不必担心数据是否为空,因为它已经被校验过了。
我们简单地使用了len()和split()的组合来计算单词的数量。 如果用户输入字数不足,我们抛出一
个forms.ValidationError型异常。这个异常的描述会被作为错误列表中的一项显示给用户。
在函数的末尾显式地返回字段的值非常重要。 我们可以在我们自定义的校验方法中修改它的值(或者把它转换
成另一种Python类型)。 如果我们忘记了这一步,None值就会返回,原始的数据就丢失掉了。
5 指定标签
HTML表单中自动生成的标签默认是按照规则生成的:用空格代替下划线,首字母大写。如email的标签
是"Email" 。(好像在哪听到过? 是的,同样的逻辑被用于模块(model)中字段的verbose_name值。 我们在
第五章谈到过。)
像在模块中做过的那样,我们同样可以自定义字段的标签。 仅需使用label,像这样:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False, **label='Your e‐mail address'** )
message = forms.CharField(widget=forms.Textarea)
6 定制Form设计
在上面的`` contact_form.html`` 模板中我们使用`` {{form.as_table}}`` 显示表单,不过我们可以使用其他更精
确控制表单显示的方法。
修改form的显示的最快捷的方式是使用CSS。 尤其是错误列表,可以增强视觉效果。自动生成的错误列表精确
的使用`` <ul class=”errorlist”>``,这样,我们就可以针对它们使用CSS。 下面的CSS让错误更加醒目了:
<style type="text/css">
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background‐color: red;
display: block;
font‐size: 10px;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
虽然,自动生成HTML是很方便的,但是在某些时候,你会想覆盖默认的显示。 {{form.as_table}}和其它的方
法在开发的时候是一个快捷的方式,form的显示方式也可以在form中被方便地重写。
每一个字段部件(<input type=”text”>, <select>, <textarea>, 或者类似)都可以通过访问{{form.字段名}}进
行单独的渲染。
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<div class="field">
{{ form.subject.errors }}
<label for="id_subject">Subject:</label>
{{ form.subject }}
</div>
<div class="field">
{{ form.email.errors }}
<label for="id_email">Your e‐mail address:</label>
{{ form.email }}
</div>
<div class="field">
{{ form.message.errors }}
<label for="id_message">Message:</label>
{{ form.message }}
</div>
<input type="submit" value="Submit">
</form>
</body>
</html>
{{ form.message.errors }} 会在 <ul class="errorlist"> 里面显示,如果字段是合法的,或者form没有被绑
定,就显示一个空字符串。 我们还可以把 form.message.errors 当作一个布尔值或者当它是list在上面做迭代,
例如:
<div class="field{% if form.message.errors %} errors{% endif %}">
{% if form.message.errors %}
<ul>
{% for error in form.message.errors %}
<li><strong>{{ error }}</strong></li>
{% endfor %}
</ul>
{% endif %}
<label for="id_message">Message:</label>
Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by
Chinese translate hosting by py3k.cn.
Document License`_.
{{ form.message }}
</div>
在校验失败的情况下, 这段代码会在包含错误字段的div的class属性中增加一个”errors”,在一个有序列表中
显示错误信息。