2 表单

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

http://www.cnblogs.com/ganiks/

6.模板和表单处理

1 模板

1.1 理解Contexts

1.2 模板语言语法

1.2.1 模板过滤器

1.2.2 标签Tag

1.2.3 Blocks和Extends

跳出当前模板和其他模板交互

1.2.4 include

2 表单

2.1 定义表单

2.1.1 基于模型的表单

2.1.2 保存ModelForm

2.1.3 区别于Model

2.1.4 继承表单

2.2 填写表单

2.3 验证和清理

2.4 显示表单

2.4.1 显示全部表单

2.4.2 逐个显示表单

2.4.3 Widget

2.4.4 重写一个变量的默认widget

1 模板Django的模板系统绝不仅仅是用于生成HTML,还有 log文件、Email正文、CSV文件等任何文本格式文件。

1.1 理解ContextsDjango 把传递给一个渲染模板的信息称之为 context, 实质上就是包含键值对的类似字典的 Context对象

准备Contexts有两种方式:

一种是上一篇中用到的,将Contexts作为参数传递

render_to_response("person/detail.html", {"person":person})

直接将数据作为render_to_response的参数传递;

或者在使用通用视图时把extra_context参数加上

return object_list(request,

queryset = Person.objects.filter(last__istartswith=last_name)

}

第二种方式是通过 context处理器, 这个东东类似中间件,可以定义各种函数,在模板渲染之前来把键值对附加到所有context上去。

这也是认证框架这样的特性,为什么能保证特定的数据在全站范围里都能访问到的原因。

def breadcrumb_PRocessor(request):

return {

'breadcrumb': request.path.split('/')

}

通常处理器都放在根目录的 context_processors.py文件中或是app的目录中;

另外还需要在 settings.py中激活才可以使用, 通常是在一个叫做TEMPLATE_CONTEXT_PROCESSORS 的元组中, 类似中间件的激活。

1.2 模板语言语法跟其他一些非xml的 模板语言如Smarty相比, Django的模板语言没有要保持 XHTML兼容性的意思,

而是用特殊的字符来把(模板变量以及逻辑命令)和静态内容(HTML)分开来。

跟其他模板语言一样,Django模板系统也有 单独命令 和 模块级命令 , 分别是{{ variable }}, {% command %}

下面的例子渲染context内容:{"title_text":"My WebPage", "object_list": ["One", "Two", "Three"]}

<html>

<head>

<title>{{ title_text }}</title>

</head>

<body>

<ul>

{% for item in object_list %}

<li>{{ item }}</li>

{% endfor %}

</ul>

</body>

</html>

陷阱:Django在模板中输出context变量的时候,会隐式调用 unicode方法, 所以对象以及其他非字符串变量会被尽量转换成 Unicode字符串。

如果你要输出没有定义unicode方法的对象,在模板里是看不到它们的,因为Python表示对象用的是 < > ,正好在html中啥也不是,故不显示。

>>> print object()

<object object at 0x40448>

1.2.1 模板过滤器类似 UNIX 管道

string|lower

person.is_avaliable|yesno:"Yes,No"1.2.2 标签Tagif, ifequal, for, endfor, block, include, extends ...

{% ifequal object_list|length 10 %}

{% if object_list|lengthis 10 %}

模块级命令如 if for , 可以修改它们的局部 context, 很实用

如 for 提供了 {{ forloop }}局部变量, 用法有 forloop.first .last .counter .counter0

跳出当前模板和其他模板交互

通过模板继承和模板包含来完成代码的组合和重用

继承通过 blocks extends 实现;包含通过 include 实现

1.2.3 Blocks和Extends{% extends %}必须在模板的顶部调用,并告知渲染引擎这个模板是从一个更高级的模板继承而来

{% blocks %}是一个模块级标签,一个模板中可以定义多个block, 预备让那些要扩展它的模板去填充的小节举个例子,三层网站布局

/

/section1/

/section2/

/section1/page1/

/section1/page2/#base.html

<html><head><title>{% block title %}My Web Site{% endblock %}</title></head></html>

<div id="content">{% block content %}{% endblock %}</div>

section1.html

{% extends "base.html" %}

{% block title %} Section1 {% endblock %}

page1.html

{% extends "section1.html" %}

{% block content %} This Page 1 {% endblock %}

page2.html

{% extends "section1.html" %}

{% block content %} This Page 2 {% endblock %}

1.2.4 include很简单,类似php的include,实现代码重用

http://www.cnblogs.com/ganiks/p/django-template-and-forms.html

2 表单Django提供了 forms 库来把框架里的三个主要的组件联系在一起:

模型里定义的数据库字段

模板里显示的HTML表单标签

验证用户输入和显示错误信息的能力2.1 定义表单表单处理的核心类Form 其实跟 Model 看上去是基本相同的, 它们都是处理 变量对象集合, 只是代表的意义不同,一个是Web表单,一个是数据表

有了Form类,我们不光可以轻松处理跟Model模型 100%匹配的表单,还可以隐藏或是省略特定变量,或是把多个model里的变量放在一个表单,或是处理和数据库存储毫无关系的表单, 非常灵活。

from django import newforms as forms

class PersonForm(forms.Form):

first = forms.CharField(max_length=100, required=True)

last = forms.CharField(max_length=100, required=True)

middle = forms.CharField(max_length=100)

2.1.1 基于模型的表单Django允许你使用Form变形 ModelForm 类为任何 Model类或实例取得一个Form子类,

一个ModelForm和普通Form基本一样,但是包含了一个Meta嵌套类(类似Model里的Meta),内含一个必须的属性 model

下面重新定义下上面的 Form

from django import newforms as forms

from mysite.myapp.models import Person

class PersonForm(forms.ModelForm):

class Meta:

model = Person

完美体现了Django的DRY don't repeat yourself 的原则

2.1.2 保存ModelForm基于模型创建的表单跟手动生成的表单有一个很重要的区别是, save方法

from mysite.myapp.forms import PersonForm

form = PersonForm({'first':'John', 'last':'Doe'})

new_person = form.save()

你经常会需要在数据,从表单提交后,存储到数据库之前,修改它们;

而最好还是在后一个时间段修改,因为这时候你修改的是Python值,而不是POST数据。

为了能让在save之前修改, save方法提供了一个可选的commit参数(默认是True), 控制你是否真的更新数据库。

from mysite.myapp.forms import PersonForm

form = PersonForm({'first':'John', 'last':'Doe'})

new_person = form.save(commit=False)

new_person.middle = 'Danger'

new_person.save()

如果使用 commit=False 来延迟保存的ModelForm包含了相关对象, Django会给表单(不是Model对象的结果)添加一个额外的方法 save_m2m, 让你正确安排时间的顺序。

form = PersonForm(input_including_related_objects)

new_person = form.save(commit=False)

new_person.middle = 'Danger'

new_person.save()

form.save_m2m()

如果没有最后的 save_m2m(), related objects会出问题的。

2.1.3 区别于Model继承模型的表单是非常方便,但是有时候我们需要排除一些变量,并不是需要所有的变量,不需要重新写一个Form子类出来,有好几种方法:

from django import newforms as forms

from mysite.myapp.models import Person

class PersonForm(forms.ModelForm):

class Meta:

model = Person

exclude = ('middle', )

class PersonForm(forms.ModelForm):

class Meta:

model = Person

fields = ('first', 'last')

这样一来,忽略的变量就不会被save方法保存,所以忽略它时要确保DB中的定义是 null=True的,否则会报错。

有时候,还需要重写forms层里的Field子类,验证和显示特定的变量,如下重新定义了first字段的长度

class PersonForm(forms.ModelForm):

first = forms.CharField(max_length=10)

class Meta:

model = Person

关于“关系表单变量” relationshipform fields

ModelChoiceField -- ForeignKey

ModelMultipleChoiceField -- ManyToManyField还记得吗?当时Model定义外键和多对多关系的时候,使用了limit_choices_to参数, 其实等效的方法可以在表单层变量里自定义一个 queryset 参数, 用来接收一个 特定的 QuerySet 对象, 如下例子Person模型有一个指向其他Person对象的没有限制的父ForeignKey:

class PersonForm(forms.ModelForm):

class Meta:

model = Person

class SmithChildForm(forms.ModelForm):

parent = forms.ModelChoiceField(queryset=Person.objects.filter(last='Smith'))

class = Meta:

model = Person

2.1.4 继承表单跟继承模型一样

from django import newforms as forms

class PersonForm(forms.Form):

first = forms.CharField()

last = forms.CharField()

class Person2Form(forms.Form):

first = forms.CharField()

last = forms.CharField()

class AgedPersonForm(PersonForm):

age = forms.IntergerField()

class MixedPerson(PersonForm, PersonForm2):

# mixed extends

2.2 填写表单Django的表单库中有2种表单

绑定的 bound, 和数据有关系

没绑定的 unbound, 没有数据表单有一个特性, 可以随便往表单的数据字典里添加额外的键值对, 表单会自动无视那些和它们定义无关的输入

from mysite.myapp.forms import PersonForm

def process_form(request):

post = request.POST.copy()

form = PersonForm(post)

还可以创建一个虽然未绑定,但是模板打印时载入显示了初始值的表单, 这个命名构造函数参数 initial 是一个字典

每个表单变量也都有一个类似的参数,允许指定它自己的默认值,不过如果有冲突的话, 表单级的 initial 会覆盖变量级的

from django import newforms as forms

from django.shotcuts import render_to_response

class PersonForm(forms.Form):

first = forms.CharField()

last = forms.CharField(initial='Smith')#表单定义时,变量级initial参数

middle = forms.CharField()

def process_form(request):

if not reuqest.POST:

form = PersonForm(initial={'first':'John'}) #创建表单实例时, 表单级initial参数,这里如果也定义了last, 则会覆盖上面的Smith

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

使用实例层initial参数的好处在于它的值可以在表单创建的时候才被构造出来, 这样一来,你可以引用在表单或是模型定义的时候还不知道的信息,特别是请求对象里的信息,看下面的例子

from django.shotcuts import get_object_or_404, render_to_response

from mysite.myapp.models import Person, PersonForm

# Views's URL /person/<id>/children/add

def add_relative(request, **kwargs):

if not request.POST:

relative = get_object_or_404(Person, pk=kwargs['id']

form = PersonForm(initial={'last': relative.last})

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

这例子中 parent 的 last 值是后来得到的,通过 initial 赋给form, 孩子自动填写好父亲的姓氏

http://www.cnblogs.com/ganiks/p/django-template-and-forms.html

2.3 验证和清理要让表单运行验证程序,可以显式使用 is_valid 方法

if request.POST:

form = PersonForm(request.POST)

if form.is_valid:

new_person = form.save()

... ...

执行完验证后,表单对象会得到两个新属性“之一”:

errors -- 包含错误信息的字典

cleaned_data -- 原来绑定到表单的值的干净版本

干净数据意义在于, 输入的数据需要规范化 --- 从一种或多种可能的输入格式转换为一个统一的输出格式,以方便验证和数据库存储

因为 request.POST 中存储的格式一般都是字符串, 经过干净之后

数字变量的字符串 -- int、long

日期变量的字符串 -- datetime2.4 显示表单每个Django表单变量都知道自己在HTML标签里要怎么显示, 这种行为是通过 widget 实现的(后面介绍)

first = forms.CharField(max_length=100, required=True)

<tr>

<th>

<label for="id_first">First:</label>

</th>

<td>

<input id="id_first" type="text" name="first" maxlength="100" />

</td>

</tr>

pf = PersonForm(auto_id=False, label_suffix='')

<tr>

<th>

<label>First</label>

</th>

<td>

<input type="text" name="first" maxlength="100" />

</td>

</tr>

pf = PersonForm(auto_id='%s_id', label_suffix='?')

<tr>

<th>

<label for="first_id">First?</label>

</th>

<td>

<input id="first_id" type="text" name="first" maxlength="100" />

</td>

</tr>

2.4.1 显示全部表单打印表单有多重方法

as_table 默认

as_ul

as_p2.4.2 逐个显示表单2.4.3 Widget每个Django表单变量都知道自己在HTML标签里要怎么显示, 这种行为是通过 widget 实现的, 这个widget子类(比如TextInput)接受了一个 attrs字典,能直接映射到HTML标签的属性上去。

middle = forms.CharField(max_length=100,

widget=forms.TextInput(attrs={'size':3})

<input id="id_middle" maxlength="100" type="text" name="middle" size="3" />

2.4.4 重写一个变量的默认widget来自定义一个widget LargeTextarea, 默认拥有 40行和100列

forms.py

from django import newforms as forms

class LargeTextareaWidget(forms.Textarea):

def __init__(self, *args, **kwargs):

kwargs.setdefault('attrs', {}).update({'rows':40, 'cols':100})

super(LargeTextareaWidget, self).__init__(*args, **kwargs))

这里的 setdefault对字典用到一个技巧,在给定的键存在情况下回返回现有的值, 若给定的键不存在,则返回提供的值;

用在这里,是确保 kwargs 关键字参数字典一定共用 attrs 字典, 不管原来的构造函数参数是什么, 可以 update 来更新attrs字典添加我们需要的默认值。

views.py

from django import newsforms as forms

from mysite.myapp.forms import LargeTextareaWidget

class ContentForm(forms.Form):

name = forms.CharField()

markup = forms.ChoiceField(choices=[('markdown', 'Markdown'),('textile', 'Textile')])

text = forms.Textarea(widget=LargeTextareaWidget)

是不是还有优化空间?

Django就是Python, 有需要的时候, 很容易把各种类和对象替换出去, 从而达到更灵活的自定义。

forms.py

from django import newforms as forms

class LargeTextareaWidget(forms.Textarea):

def __init__(self, *args, **kwargs):

kwargs.setdefault('attrs', {}).update({'rows':40, 'cols':100})

super(LargeTextareaWidget, self).__init__(*args, **kwargs))

class LargeTextarea(forms.Field):

widget = LargeTextareaWidget

现在可以更方便的使用这个自定义的widget

views.py

from django import newsforms as forms

from mysite.myapp.forms import LargeTextareaWidget

class ContentForm(forms.Form):

name = forms.CharField()

markup = forms.ChoiceField(choices=[('markdown', 'Markdown'),('textile', 'Textile')])

#text = forms.Textarea(widget=LargeTextareaWidget)

text = LargeTextarea()

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航