Django newforms

来源:互联网 发布:汽车修理软件哪个好 编辑:程序博客网 时间:2024/05/01 23:36

由于前两天被 django forms 中的 manipulator 弄怕了,觉得这个东西比较难用。在 python-chinese 邮件列表中提问后,按照建议,我开始学习 newforms 了。本文是一些摘要。

newforms 的第一个好处是不必和 model 耦合,专门负责 html 的显示和验证。并且调试相对简便,我们随时可以通过 print 来输出其将要 render 的 html.

如何定义 Form 类

Form 类可以分为两种:绑定数据的和不绑定数据的。对于绑定数据的 Form, 可以进行验证(validate).
而 Form 可以有多种办法来创建。可以通过子类化的方式完全定制(继承 django.newforms.Form);也可以用一些帮助方法,直接返回一个定制的 Form 实例。比如:

if id is None:
    EntryForm 
= forms.models.form_for_model(Entry)
else:
    entry 
= Entry.objects.get(id=id)
    EntryForm 
= forms.models.form_for_instance(entry)

这段代码演示了从模型或模型类的实例直接创建相应 Form 的用法。对于简单的情形这样做应该是没问题的。

完全定制的做法:

>>> class PersonForm(Form):
     first_name 
= CharField()
     last_name 
= CharField()
>>> class InstrumentForm(Form):
     instrument 
= CharField()
>>> class BeatleForm(PersonForm, InstrumentForm):
     haircut_type 
= CharField()
>>> b = BeatleForm(auto_id=False)
>>> print b.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>

这个例子表明在子类化 Form 的时候,甚至可以用多继承。

Form 的实例化

Form 的构造器中可以传递一个字典,代表其中包含的数据,这种情况下 Form 被称之为是“绑定的”;而如果不传递任何数据,则称为“非绑定的”。

# 绑定数据的 Form
= SomeForm({"email""test@test.com""username""abc"})
# 非绑定的 Form
f2 = SomeForm()

通过 f.is_bound 可以判断一个 form 是否绑定了数据。需要注意的是,数据目前被设计为不可变的,即一旦传递给 f 对象的构造器,则没有办法改变它。

Form 的输出形式

Form 的输出形式,默认的有如下几种:

print f.as_p() # 每个字段输出为一个 <p/> 标签
print f.as_table() # 表格,这是默认情形
print f.as_ul() # <ul/>
print f # 和 print f.as_table() 等效

验证数据

直接用 f.is_valid() 即可。这个操作对非绑定的 Form 无意义。
如果存在错误,则 f.errors 中包含了各字段的错误信息。该属性是一个字典,以 field 名称为 key.
如果你直接访问 f.errors,并不需要先调用 f.is_valid(),Django 会自动调用它的。

newforms 设计中的另一个好处是,通过 f.clean_data 可以获取验证后的数据。这些数据的格式是统一的形式,不管他们输入时是什么样的。比如对于日期字段,通过这个属性,最终得到的都是 python 的 datetime.date 类型。

另外一个重要的话题是关于 Fields,这一块比较琐碎,具体的描述可以看文档。值得记一下的几个要点:

1. Field 的 clean() 方法,用于验证数据;
2. Field 默认是必填的;(对应于构造器中的 required 参数)
3. Field 可以指定用于输出 HTML 的具体 widget(小控件)。
    比如我们要把一个字段显示为富文本控件,就可以创建自定义的 Widget 来实现。


代码示例

摘自:http://code.pui.ch/2007/01/07/using-djangos-newforms/
def add_edit_entry(request, id=None):
    
if id is None:
        EntryForm 
= forms.models.form_for_model(Entry)
    
else:
        entry 
= Entry.objects.get(id=id)
        EntryForm 
= forms.models.form_for_instance(entry)
    EntryForm.fields[
'detail'].widget = TinyMCE()
    
if request.method == 'POST':
        form 
= EntryForm(request.POST)
        
if form.is_valid():
            entry 
= form.save(commit=False)
            
if id is None:
                entry.owner 
= request.user
            entry.save()
            
return HttpResponseRedirect("/")
    
else:
        form 
= EntryForm()
    t 
= loader.get_template('add_entry.html')
    c 
= Context({
        
'form': form,
        
'html_head''<script src="/media/tiny_mce/tiny_mce_src.js" type="text/javascript"></script>'
    })
    
return HttpResponse(t.render(c))

add_entry.html
{% extends "base.html" %}

{% block content %}
<form action="." method="post">
  
<table class="form">
    {{ form }}
  
</table>
  
<input type="submit" value="speichern" />
</form>
{% endblock %}

以上这段代码是个简单的范本,其中没有用到自定义 Form. 因此更灵活的用法还需要我们继续去发掘。

参考资源

http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/forms/tests.py
http://code.pui.ch/2007/01/07/using-djangos-newforms/
http://www.mikecantelon.com/?q=node/22