认识django2.0读书笔记(7)---第七章 表单

时间:2021-05-05 19:18:15

文档下载地址:Django_2.0_中文教程  http://download.csdn.net/detail/julius_lee/6620099

在线地址:http://djangobook.py3k.cn/2.0/

Django 2.0 Book 关键内容记录,主要是为了帮助记忆和理清整个框架,同时以后忘了可以查看,回想。

 

介绍django对用户通过表单的提交进行的数据访问,有效性检查,及其处理

1、   request对象获取数据

示例:view视图函数

from django.http import HttpResponse



def hello(request):

return HttpResponse("Hello world")

HttpRequest对象包含当前请求URL的一些信息:

属性/方法

说明

举例

request.path

除域名以外的请求路径,以正斜杠开头

"/hello/"

request.get_host()

主机名(比如,通常所说的域名)

"127.0.0.1:8000" or "www.example.com"

request.get_full_path()

请求路径,可能包含查询字符串

"/hello/?print=true"

request.is_secure()

如果通过HTTPS访问,则此方法返回True, 否则返回False

True 或者 False2

在view函数里,要始终用这个属性或方法来得到URL,而不要手动输入。 这会使得代码更加灵活,以便在其它地方重用。下面是一个简单的例子:

# BAD!

def current_url_view_bad(request):

return HttpResponse("Welcome to the page at /current/")



# GOOD

def current_url_view_good(request):

return HttpResponse("Welcome to the page at %s" %request.path)
这样,当收到请求后,直接转为请求的路径,以后修改都不用再改视图函数了。

 

关于request.META

request.META是一个字典,包含http请求的Header信息,内容如下:

代码:

def display_meta(request):

values = request.META.items()

values.sort()

html = []

for k, v in values:

html.append('<tr><td>%s</td><td>%s</td></tr>'% (k, v))

return HttpResponse('<table>%s</table>' % '\n'.join(html))
结果:

CONTENT_LENGTH

 

CONTENT_TYPE

text/plain

CSRF_COOKIE

vslS1e5VacqktmIG0ZnQMX5KJ1T7XxLV

DJANGO_SETTINGS_MODULE

mysite.settings

GATEWAY_INTERFACE

CGI/1.1

HOME

/home/loongson

HTTP_ACCEPT

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

HTTP_ACCEPT_ENCODING

gzip, deflate

HTTP_ACCEPT_LANGUAGE

zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3

HTTP_CONNECTION

keep-alive

HTTP_COOKIE

bdshare_firstime=1361237552004; csrftoken=vslS1e5VacqktmIG0ZnQMX5KJ1T7XxLV; sessionid=smdblfqnq9kio5syti5vmqgdo8pqek7r

HTTP_DNT

1

HTTP_HOST

172.16.3.62:8080

HTTP_USER_AGENT

Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0

LANG

zh_CN.UTF-8

LANGUAGE

zh_CN:zh

LOGNAME

loongson

LS_COLORS

rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:

MAIL

/var/mail/loongson

OLDPWD

/home/loongson

PATH

/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

PATH_INFO

/values/

PWD

/home/loongson/python/django/second_poll

QUERY_STRING

 

REMOTE_ADDR

172.16.7.94

REMOTE_HOST

 

REQUEST_METHOD

GET

RUN_MAIN

true

SCRIPT_NAME

 

SERVER_NAME

LOonux-3.local

SERVER_PORT

8080

SERVER_PROTOCOL

HTTP/1.1

SERVER_SOFTWARE

WSGIServer/0.1 Python/2.6.6

SHELL

/bin/bash

SHLVL

1

SSH_CLIENT

172.16.7.94 65295 22

SSH_CONNECTION

172.16.7.94 65295 172.16.3.62 22

SSH_TTY

/dev/pts/1

TERM

xterm

TZ

Asia/Shanghai

USER

loongson

XDG_RUNTIME_DIR

/run/user/loongson

XDG_SESSION_COOKIE

51a0886c4aebc7a8473cc3a2000008c4-1385514067.991625-1414976123

XDG_SESSION_ID

194c

_

/usr/bin/python

wsgi.errors

 

wsgi.file_wrapper

wsgiref.util.FileWrapper

wsgi.input

 

wsgi.multiprocess

False

wsgi.multithread

True

wsgi.run_once

False

wsgi.url_scheme

http

wsgi.version

(1, 0)

注意:

因为request.META 是一个普通的Python字典,因此当试图访问一个不存在的键时,会触发一个KeyError异常。 (HTTP header信息是由用户的浏览器所提交的、不应该给予信任的“额外”数据,因此应该好好设计你的应用以便当一个特定的Header数据不存在时,给出一个优雅的回应。)用 try/except 语句,或者用Python字典的 get() 方法来处理这些“可能不存在的键”:

示例:

# BAD!

def ua_display_bad(request):

ua = request.META['HTTP_USER_AGENT'] # Might raise KeyError!

return HttpResponse("Your browser is %s" % ua)



# GOOD (VERSION 1)

def ua_display_good1(request):

try:

ua = request.META['HTTP_USER_AGENT']

except KeyError:

ua = 'unknown'

return HttpResponse("Your browser is %s" % ua)



# GOOD (VERSION 2)

def ua_display_good2(request):

ua = request.META.get('HTTP_USER_AGENT', 'unknown')

return HttpResponse("Your browser is %s" % ua)

使用try或者get避免header数据不存在引发的异常。

 

2、   提交数据信息

HttpRequest 还包含用户提交的信息:request.GET和request.POST,为类字典对象。

request.GET和request.POST都有get()、keys()和values()方法,你可以用用 for key in request.GET 获取所有的键。

POST数据是来自HTML中的〈form〉标签提交的,而GET数据可能来自〈form〉提交也可能是URL中的查询字符串(the query string)。

 

3、   表单处理示例

表单开发分为:前端HTML页面接口,后台view函数对提交数据处理过程

1)  创建搜索表单

示例:books目录下创建views.py

from django.shortcuts importrender_to_response

def search_form(request):

return render_to_response('search_form.html')

再在templates中创建search_form.html模板

<html>

<head>

<title>Search</title>

</head>

<body>

<form action="/search/" method="get">

<input type="text" name="q">

<input type="submit" value="Search">

</form>

</body>

</html>

最后添加URLpattern到urls.py中

from mysite.books import views

urlpatterns = patterns('',

#...

(r'^search-form/$', views.search_form),

#...

)

这样就可以出现一个搜索框在页面左上角了;也就是修改三个地方,view函数,url地址和html文件。Html文件需要了解其语法,才好书写。

但提交数据会报错404,因为form指向的search还没有实现;

需要添加第二个视图,并设置url如下:

 
# urls.py


urlpatterns = patterns('',

#...

(r'^search-form/$', views.search_form),#注意变量的写法,文件名.函数名

(r'^search/$', views.search),

#...

)


# views.py


def search(request):

if 'q' in request.GET:

message = 'You searched for: %r' % request.GET['q']#q源于html文档的name定义

else:

message = 'You submitted an empty form.'

return HttpResponse(message)

  1. HTML里我们定义了一个变量q。当提交表单时,变量q的值通过GET(method=”get”)附加在URL /search/上。注意q是在html中自定义的,并不是默认的或者没有根据得来的。
  1. 处理/search/(search())的视图通过request.GET来获取q的值。

需要注意的是在这里明确地判断q是否包含在request.GET中。就像上面request.META小节里面提到,对于用户提交过来的数据,甚至是正确的数据,都需要进行过滤。 在这里若没有进行检测,那么用户提交一个空的表单将引发KeyError异常

确认数据有效后,下一步将从数据库查询数据。

from django.http import HttpResponse

from django.shortcuts importrender_to_response

from mysite.books.models import Book


def search(request):

if 'q' in request.GET and request.GET['q']:

q = request.GET['q']

books = Book.objects.filter(title__icontains=q)#使用icontains查询,赋值给html中的books

return render_to_response('search_results.html',

{'books': books, 'query': q})#返回字典查询结果,query是查询的q 变量

else:

return HttpResponse('Please submit a search term.')


作用:

除了检查q是否存在于request.GET之外,我们还检查来reuqest.GET[‘q’]的值是否为空;

使用Book.objects.filter(title__icontains=q)获取数据库中标题包含q的书籍;

给模板传递来books,一个包含Book对象的列表;

查询结果的显示模板search_results.html如下:

<p>You Searched for :<strong>{{query }}</strong></p>


{% if books %}#books也就是q值,源于render_to_response

<p>Found {{ books|length }} book{{ books|pluralize }}.</p>#pluralize这个过滤器在适当的时候会输出s(例如找到多本书籍)

<ul>

{% for book in books %}

<li>{{ book.title }}</li>

{% endfor %}

</ul>

{% else %}

<p>NO books matched your search criteria.</P>

{% endif %}

~

结果:

找到:

YouSearched for :Nono

Found 1 book.

 Nono

没有找到:

    YouSearched for :Nono334

NO books matched your search criteria.

其界面如下图所示:

     认识django2.0读书笔记(7)---第七章 表单

认识django2.0读书笔记(7)---第七章 表单

认识django2.0读书笔记(7)---第七章 表单


4、   改进表单

首先,search()视图对于空字符串的处理相当薄弱——仅显示一条”Please submit a search term.”的提示信息。 若用户要重新填写表单必须自行点击“后退”按钮, 这种做法既糟糕又不专业。

在检测到空字符串时更好的解决方法是重新显示表单,并在表单上面给出错误提示以便用户立刻重新填写。最简单的实现方法既是添加else分句重新显示表单,代码如下:

from django.http import HttpResponse

from django.shortcuts importrender_to_response

from mysite.books.models import Book



def search_form(request):

return render_to_response('search_form.html')



def search(request):

if 'q' in request.GET and request.GET['q']:

q = request.GET['q']

books = Book.objects.filter(title__icontains=q)

return render_to_response('search_results.html',

{'books': books, 'query': q})

else:

**return render_to_response('search_form.html', {'error': True})**#字符串为空时重新显示search_form.html


改进search()视图:在字符串为空时重新显示search_form.html。 并且给这个模板传递了一个变量error,记录错误提示信息。 现在我们编辑一下search_form.html,检测变量error,如下:

<html>

<head>

<title>Search</title>

</head>

<body>

**{% if error %}**#如果有错,则显示下列信息

**<p style="color: red;">Please submit a searchterm.</p>**

**{% endif %}**

<form action="/search/" method="get">

<input type="text" name="q">

<input type="submit" value="Search">

</form>

</body>

</html>
 

但是现在出现一个问题: 是否有必要专门编写search_form()来显示表单? 按实际情况来说,当一个请求发送至/search/(未包含GET的数据)后将会显示一个空的表单(带有错误信息)。 所以,需要改变search()视图:当用户访问/search/并未提交任何数据时就隐藏错误信息,这样就移去search_form()视图以及 对应的URLpattern。

def search(request):

error = False

if 'q' in request.GET:

q = request.GET['q']

if not q:# 用户提交了一个空表单,那么它将看到错误提示信息,还有表单

error = True

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',

{'error': error})#用户访问/search/并且没有带有GET数据。则报错


在改进后的视图中,若用户访问/search/并且没有带有GET数据,那么他将看到一个没有错误信息的表单; 如果用户提交了一个空表单,那么它将看到错误提示信息,还有表单;最后,若用户提交了一个非空的值,那么他将看到搜索结果

既然已经将两个视图与URLs合并起来,/search/视图管理着表单的显示以及结果的显示,那么在search_form.html里表单的action值就没有必要硬编码的指定URL。 原先的代码是这样:

<form action="/search/"method="get">

现在改成这样:

<form action=""method="get">

action=”“意味着表单将提交给与当前页面相同的URL。

 

5、   简单的验证

主要是针对目前的数据验证太过简单,实际中会遇到特定格式的验证,如邮件地址,邮编,日期等。

解决办法:

Javascript验证

服务器端验证

示例:

修改view函数

def search(request):

**errors = []**

if'q' in request.GET:

q = request.GET['q']

if not q:

**errors.append('Enter a search term.')**#利用append给出对应出错提示

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** })
修改search_form.html文件

 

<html>

<head>

<title>Search</title>

</head>

<body>

**{% if errors %}**

**<ul>**

**{% for error in errors %}**#显示一个errors列表

**<li>{{ error }}</li>**

**{% endfor %}**

**</ul>**

**{% endif %}**

<form action="/search/" method="get">

<input type="text"name="q">

<input type="submit" value="Search">

</form>

</body>

</html>

6、   编写contact表单

示例:联系站点的表单

表单内容:用户反馈信息,email回信地址;表单提交验证后,系统自动发送email给站点人员

准备:新建一个contact文件夹在project下面,与books同级,建立空文件__init__.py

1)编写contact_form.html,定义主题,email和反馈信息

<html>

<head>

<title>Contactus</title>

</head>

<body>

<h1>Contactus</h1>



{% if errors %}#如果有错,则显示错误信息

<ul>

{% for error inerrors %}

<li>{{ error}}</li>

{% endfor %}

</ul>

{% endif %}



<formaction="/contact/" method="post">#method="post"会进行服务器端操作,发送email

<p>Subject:<input type="text" name="subject"></p>#标题

<p>Your e-mail(optional): <input type="text"name="email"></p>

<p>Message:<textarea name="message" rows="10"cols="50"></textarea></p>

<inputtype="submit" value="Submit">

</form>

</body>

</html>

2)  编写contact视图

from django.core.mail import send_mail

from django.http import HttpResponseRedirect

from django.shortcuts importrender_to_response



def contact(request):

errors = []

if request.method == 'POST':#<!--使用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})


说明:

使用request.POST代替request.GET来获取提交过来的数据。 这是必须的,因为contact_form.html里表单使用的是method=”post”。如果在视图里通过POST获取数据,那么request.GET将为空。

有两个必填项,subject和 message,所以需要对这两个进行验证。注意,使用request.POST.get()方法,并提供一个空的字符串作为默认值;这个方法很好的解决了键丢失与空数据问题。

虽然email非必填项,但如果有提交的值则也需进行验证。验证算法相当的薄弱,仅验证值是否包含@字符。 在实际应用中,需要更为健壮的验证机制(Django提供这些验证机制)。

使用了django.core.mail.send_mail函数来发送e-mail。 这个函数有四个必选参数: 主题,正文,寄信人和收件人列表。 send_mail是Django的EmailMessage类的一个方便的包装,EmailMessage类提供了更高级的方法,比如附件,多部分邮 件,以及对于邮件头部的完整控制。

当邮件发送成功之后,使用HttpResponseRedirect对象将网页重定向至一个包含成功信息的页面。但是要解释一下为何重定向至新的页面,而不是在模板中直接调用render_to_response()来输出:原因就是: 若用户刷新一个包含POST表单的页面,那么请求将会重新发送造成重复。 这通常会造成非期望的结果,比如说重复的数据库记录;在例子中,将导致发送两封同样的邮件。

应每次都给成功的POST请求做重定向。 这就是web开发的最佳实践。

3)  表单的重新显示

数据验证失败后返回表单中原来提交的数据,就不用再填写一次正确的数据了。通过手动将原来提交的数据返回给模板,编辑html里的各字段填充原来的值

示例:

# views.py

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,

**'subject': request.POST.get('subject', ''),**

**'message': request.POST.get('message', ''),**

**'email': request.POST.get('email', ''),**

})
 
# contact_form.html<html><head>   <title>Contact us</title></head><body>    <h1>Contact us</h1>     {% if errors %}        <ul>            {% for error in errors %}            <li>{{ error }}</li>            {% endfor %}        </ul>    {% endif %}     <form action="/contact/"method="post"> <!--增加value值-->        <p>Subject: <input type="text" name="subject" **value="{{ subject}}"** ></p>        <p>Your e-mail (optional):<input type="text" name="email" **value="{{ email}}"** ></p>        <p>Message: <textarea name="message" rows="10" cols="50">**{{message }}**</textarea></p>        <input type="submit"value="Submit">    </form></body></html>


7、   第一个form类

Django.forms库,处理html表单显示及验证

在存放views.py的目录中创建form.py文件

from django import forms



class ContactForm(forms.Form):

subject = forms.CharField()#使用charField类型

email = forms.EmailField(required=False)#emailFild类型,false表示email是可选项

message = forms.CharField()


实际上,这个类就是将对应的subject,email等内容格式化成为html内容,添加标签等

示例:

>>> from contact.forms importContactForm

>>> f = ContactForm()

>>> print f

<tr><th><labelfor="id_subject">Subject:</label></th><td><inputtype="text" name="subject" id="id_subject"/></td></tr>

<tr><th><labelfor="id_email">Email:</label></th><td><inputtype="text" name="email" id="id_email"/></td></tr>

<tr><th><labelfor="id_message">Message:</label></th><td><inputtype="text" name="message" id="id_message"/></td></t


其次,进行数据的校验

>>> f = ContactForm({'subject':'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})

>>> f.is_bound

True


例如以上创建了一个新的Form对象,并且传入一个与定义匹配的字典类型数据,对一个Form实体赋值,得到了一个绑定form,调用任何绑定form的is_valid()方法,就可以知道它的数据是否合法

>>> f.is_valid()

True


1)视图中使用form对象

示例:使用forms框架重写contact

# views.py


from django.shortcuts importrender_to_response

from mysite.contact.forms importContactForm



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>
 

2)改变字段显示

在本地显示这个表单的时,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** )# forms框架把每一个字段的显示逻辑分离到一组部件(widget)中


4)  设置最大长度

经常使用的校验要求是检查字段长度。

from django import forms



class ContactForm(forms.Form):

subject = forms.CharField(**max_length=100** )#这样显示时使subject限制在100字符内

email = forms.EmailField(required=False)

message = forms.CharField(widget=forms.Textarea)
类似的还有min_length


5)  设置初始值

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!'}**#为subject字段添加初始值

)

return render_to_response('contact_form.html', {'form': form})


注意,传入* 初始值* 数据和传入数据以* 绑定* 表单是有区别的。 最大的区别是,如果仅传入* 初始值* 数据,表单是unbound的,那意味着它没有错误消息。

6)  自定义校验规则

示例:对提交的消息规定必须大于4个字符,并创建自定义校验字段类型,希望`` message`` 字段有一个额外的校验,我们增加一个`` clean_message()`` 方法到`` Form`` 类:clean_message()方法将在指定字段的默认校验逻辑执行* 之后* 被调用。因为字段数据已经被部分处理,所以它被从self.cleaned_data中提取出来了;

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)



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
 

简单地使用了len()和split()的组合来计算单词的数量。 如果用户输入字数不足,我们抛出一个forms.ValidationError型异常。这个异常的描述会被作为错误列表中的一项显示给用户。

在函数的末尾显式地返回字段


7)  指定标签

需使用label,像这样:

class ContactForm(forms.Form):

subject = forms.CharField(max_length=100)

email = forms.EmailField(required=False, **label='Your e-mail address'**)#label自定义标签

message = forms.CharField(widget=forms.Textarea)


8)定制form设计

在上面`` contact_form.html``模板中我们使用``{{form.as_table}}`` 显示表单,不过可以使用其他更精确控制表单显示的方法,示例:

<style type="text/css">

ul.errorlist {

margin: 0;

padding: 0;

}

.errorlist li {

background-color: red;

color: white;

display: block;

font-size: 10px;

margin: 0 0 3px;

padding: 4px 5px;

}

</style>


修改form的显示的最快捷的方式是使用CSS。自动生成的错误列表精确的使用`` <ulclass=”errorlist”>``

每一个字段部件(<inputtype=”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{% ifform.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>

{{ form.message }}

</div>


在校验失败的情况下, 这段代码会在包含错误字段的div的class属性中增加一个”errors”,在一个有序列表中显示错误信息。

 这一章总结了本书的“核心教程”。


前七章介绍的内容就到此结束,后续再补充一些练习,巩固后再继续后续章节;

后面部分,从第八章到第十二章,将详细讲述高级(进阶)使用,包括如何配置一个Django应用程序(第十二章)。