Django 表单类详解

本文纯手工搬运,为自己学习记录使用.

Django带有一个form库,称为django.forms

表单框架最主要的用法是,为每一个将要处理的HTML的

定义一个 Form 类

from django import forms
class ContactForm(forms.Form):
     subject = forms.CharField()
     email = forms.EmailField(required=False)
     message = forms.CharField()

这看上去简单易懂,并且很像在模块中使用的语法。 表单中的每一个字段(域)作为 Form 类的属性,被展现
成 Field 类。这里只用到 CharField 和 EmailField 类型。 每一个字段都默认是必填。要使 email 成为可选项,我
们需要指定 required=False 。
让我们钻研到Python解释器里面看看这个类做了些什么。 它做的第一件事是将自己显示成HTML:

>>> from contact.forms import ContactForm
>>> f = ContactForm()
>>> print f
Email:Subject: <
  • < >>> print f.as_p()

  • 请注意,标签

      、的开闭合标记没有包含于输出当中,这样你就可以添加额外的行或者自定义格式。
      这些类方法只是一般情况下用于快捷显示完整表单的方法。 你同样可以用HTML显示个别字段:

      >>> print f['subject']
      
      >>> print f['message']
      
      

      Form 对象做的第二件事是校验数据。 为了校验数据,我们创建一个新的对 Form 象,并且传入一个与定义匹配的字典类型数据:

      >>> f = ContactForm({'subject': 'Hello', 'email': '[email protected]', 'message': 'Nice site!'})
      

      一旦你对一个 Form 实体赋值,你就得到了一个绑定form:

      >>> f.is_bound
      True
      

      调用任何绑定form的 is_valid() 方法,就可以知道它的数据是否合法。 我们已经为每个字段传入了值,因此整个 Form 是合法的:

      >>> f.is_valid()
      True
      

      如果我们不传入 email 值,它依然是合法的。因为我们指定这个字段的属性 required=False :

      >>> f = ContactForm({'subject': 'Hello', 'message': 'Nice site!'})
      >>> f.is_valid()
      True
      

      但是,如果留空 subject 或 message ,整个 Form 就不再合法了:

      >>> f = ContactForm({'subject': 'Hello'})
      >>> f.is_valid()
      False
      >>> f = ContactForm({'subject': 'Hello', 'message': ''})
      >>> f.is_valid()
      False
      

      你可以逐一查看每个字段的出错消息:

      >>> f = ContactForm({'subject': 'Hello', 'message': ''})
      >>> f['message'].errors
      [u'This field is required.']
      >>> f['subject'].errors
      []
      >>> f['email'].errors
      []
      

      每一个邦定 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: [email protected], message: Nice site!})
      >>> f.is_valid()
      True
      >>> f.cleaned_data
      {message': uNice site!, email: [email protected], subject: uHello}
      

      我们的contact form只涉及字符串类型,它们会被清理成Unicode对象。如果我们使用整数型或日期型,form框架会确保方法使用合适的Python整数型或 datetime.date 型对象。

      在视图中使用Form对象

      在学习了关于 Form 类的基本知识后,你会看到我们如何把它用到视图中,取代 contact() 代码中不整齐的部分。一下示例说明了我们如何用forms框架重写 contact() :

      # views.py
      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', '[email protected]'),
                  ['[email protected]'],
              )
              return HttpResponseRedirect('/contact/thanks/')
          else:
              form = ContactForm()
          return render_to_response('contact_form.html', {'form': form})
      
      # contact_form.html
      
      
          Contact us
      
      
          

      Contact us

      {% if form.errors %}

      Please correct the error{{ form.errors|pluralize }} below.

      {% endif %}
    {{ form.as_table }}

    改变字段显示

    你可能首先注意到:当你在本地显示这个表单的时, 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)中。 每一个字段类型都拥有一个默认的部件,我们也可以容易地替换掉默认的部件,或者提供一个自定义的部件。

    设置最大长度

    一个最经常使用的校验要求是检查字段长度。 另外,我们应该改进 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 参数同样可用。

    设置初始值

    让我们再改进一下这个表单:为字 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', `'[email protected]`_'),
                    [`'[email protected]`_'],
                    )
                return HttpResponseRedirect('/contact/thanks/')
            else:
                form = ContactForm(
                    **initial={'subject': 'I love your site!'}**
                    )
                return render_to_response('contact_form.html', {'form': form})
    

    现在, subject 字段将被那个句子填充。
    请注意,传入* 初始值* 数据和传入数据以* 绑定* 表单是有区别的。 最大的区别是,如果仅传入* 初始值* 数据,表单是 unbound 的,那意味着它没有错误消息。

    自定义校验规则

    假设我们已经发布了反馈页面了,email已经开始源源不断地涌入了。 这里有一个问题: 一些提交的消息只有一两个字,我们无法得知详细的信息。 所以我们决定增加一条新的校验: 来点专业精神,最起码写四个字,拜托。
    我们有很多的方法把我们的自定义校验挂在Django的form上。 如果我们的规则会被一次又一次的使用,我们可以创建一个自定义的字段类型。 大多数的自定义校验都是一次性的,可以直接绑定到form类.
    我们希望message 字段有一个额外的校验,我们增加一个clean_message() 方法到Form 类:

    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
    

    Django的form系统自动寻找匹配的函数方法,该方法名称以 clean_ 开头,并以字段名称结束。 如果有这样的方法,它将在校验时被调用。
    特别地, clean_message() 方法将在指定字段的默认校验逻辑执行* 之后* 被调用。(本例中,在必填 CharField 这个校验逻辑之后。)因为字段数据已经被部分处理,所以它被从 self.cleaned_data 中提取出来了。同样,我们不必担心数据是否为空,因为它已经被校验过了。
    我们简单地使用了len()和split()的组合来计算单词的数量。 如果用户输入字数不足,我们抛出一个 forms.ValidationError 型异常。这个异常的描述会被作为错误列表中的一项显示给用户。
    在函数的末尾显式地返回字段的值非常重要。 我们可以在我们自定义的校验方法中修改它的值(或者把它转换成另一种Python类型)。 如果我们忘记了这一步,None值就会返回,原始的数据就丢失掉了。

    指定标签

    HTML表单中自动生成的标签默认是按照规则生成的:用空格代替下划线,首字母大写。如 email 的标签是 "Email" 。
    像在模块中做过的那样,我们同样可以自定义字段的标签。 仅需使用 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)
    

    虽然,自动生成HTML是很方便的,但是在某些时候,你会想覆盖默认的显示。 {{form.as_table}}和其它的方法在开发的时候是一个快捷的方式,form的显示方式也可以在form中被方便地重写。
    每一个字段部件(,