Django forms 阅读笔记

Django 的版本变化太快,1.6的文档已经显得过时了,我真的是醉了。

https://docs.djangoproject.com/en/1.6/topics/forms/

主要内容:
概览
在视图(view)里使用form
上传文件
如何从form里取出数据
在模板上显示form
form与跨站请求攻击
如何定制form生成的HTML
循环form域
如何处理可见域和隐藏域
form模板的复用

Working with forms

About this document

This document provides an introduction to Django’s form handling features. For a more detailed look at specific areas of the forms API, see The Forms APIForm fields, and Form and field validation.

django.forms is Django’s form-handling library.

While it is possible to process form submissions just using Django’s HttpRequest class, using the form library takes care of a number of common form-related tasks. Using it, you can:  ★ 使用 form 你能够得到以下好处 

  1. Display an HTML form with automatically generated form widgets.  ★ 自动生成 HTML 
  2. Check submitted data against a set of validation rules. ★ 用一系列的校验规则检查提交的数据
  3. Redisplay a form in the case of validation errors.  ★ 在 validation error(检查错误)时重新显示 form 数据 
  4. Convert submitted form data to the relevant Python data types.  ★ 把提交的 form 数据转化成相应的 Python 数据类型 

Overview

The library deals with these concepts:

Widget
A class that corresponds to an HTML form widget, e.g.  <input type="text"> or  <textarea>. This handles rendering of the widget as HTML.

★ 一个部件类,负责把 HTML form 部件渲染(转变)成 HTML。  

Field
A class that is responsible for doing validation, e.g. an  EmailField that makes sure its data is a valid email address.   ★ 负责验证的类 
Form
A collection of fields that knows how to validate itself and display itself as HTML.   ★ fields 的集合,能够验证自身 或 把自身显示成 HTML 
Form Assets (the  Media class)
The CSS and JavaScript resources that are required to render a form.   ★ Media 类,包含渲染 form 时所用的 CSS 和 JavaScript  

The library is decoupled from the other Django components, such as the database layer, views and templates. It relies only on Django settings, a couple of django.utils helper functions and Django’s internationalization hooks (but you’re not required to be using internationalization features to use this library).

★ 此类库解耦其它 django 模块,仅仅依赖 django settings。

Form objects

A Form object encapsulates a sequence of form fields and a collection of validation rules that must be fulfilled in order for the form to be accepted. Form classes are created as subclasses of django.forms.Form and make use of a declarative style that you’ll be familiar with if you’ve used Django’s database models.

★ 一个Form 对象包含了一系列的域(field)和校验的规则, 编写Form必须继承 django.forms.Form,然后声明式的定义数据,这和定义 Django db models 是类似的

For example, consider a form used to implement “contact me” functionality on a personal Web site:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

A form is composed of Field objects. In this case, our form has four fields: subjectmessagesender and cc_myselfCharFieldEmailField and BooleanField are just three of the available field types; a full list can be found in Form fields.  ★ 一个 form 由若干 Field 对象组成。这里的 form 有四个域:subject, message, sender 和 cc_myself.  CharField, EmailField, BooleanField 是三种域类型,域类型的完整列表在Form fields 里。

If your form is going to be used to directly add or edit a Django model, you can use a ModelForm to avoid duplicating your model description.

★ 如果 form 在 一个 model 基础上添加和编辑field,可以使用 ModelForm 避免重复劳动。

Using a form in a view

The standard pattern for processing a form in a view looks like this:

from django.shortcuts import render
from django.http import HttpResponseRedirect

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        # ContactForm was defined in the previous section
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        form = ContactForm() # An unbound form

    return render(request, 'contact.html', {
        'form': form,
    })

★以上演示如何在view里使用定义好的form

There are three possible code paths here:

Form submitted? Data? What occurs
Unsubmitted None yet Template gets passed unbound instance of ContactForm.
Submitted Invalid data Template gets passed bound instance of ContactForm.
Submitted Valid data Valid data is processed. Redirect to a “thanks” page.

The distinction between Bound and unbound forms is important:

  • An unbound form has no data associated with it. When rendered to the user, it will be empty or will contain default values.
  • A bound form has submitted data, and hence can be used to tell if that data is valid. If an invalid bound form is rendered, it can include inline error messages telling the user what data to correct.

★讲了form的两种状态:未绑定和绑定。未绑定的 form 没有关联任何数据,或者为空或者包含默认的数据;绑定的 form 包含提交的数据,可以在数据判定是合法数据后使用。

Handling file uploads with a form

To see how to handle file uploads with your form, see Binding uploaded files to a form.

★用form上传文件,有特殊的规则

Processing the data from a form

Once is_valid() returns True, the successfully validated form data will be in the form.cleaned_data dictionary. This data will have been converted nicely into Python types for you.

★ 当 form 验证合格(is_valid() == True)时,用 form.cleaned_data 字典来取得数据。

Note

You can still access the unvalidated data directly from request.POST at this point, but the validated data is better.  

★ 仍然可以从 request.POST 访问未检查的变量,但是检查过的变量更好

In the above example, cc_myself will be a boolean value. Likewise, fields such as IntegerField and FloatField convert values to a Python int and float respectively. 

★ 上面的例子中,cc_myself 应该是一个布尔值。同样,IntegerField 和 FloatField 会转换成 int 型和 float 型。

Read-only fields are not available in form.cleaned_data (and setting a value in a custom clean() method won’t have any effect). These fields are displayed as text rather than as input elements, and thus are not posted back to the server.

★ 只读域不在 form.cleaned_data 里(在定制的 clean() 方法里设置值没有任何效果)。这些域会被显示成 text 。

Extending the earlier example, here’s how the form data could be processed:

if form.is_valid():
    subject = form.cleaned_data['subject']
    message = form.cleaned_data['message']
    sender = form.cleaned_data['sender']
    cc_myself = form.cleaned_data['cc_myself']

    recipients = ['info@example.com']
    if cc_myself:
        recipients.append(sender)

    from django.core.mail import send_mail
    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect('/thanks/') # Redirect after POST

★这是使用form.cleaned_data字典来取得数据的例子。

Tip

For more on sending email from Django, see Sending email.

Displaying a form using a template

Forms are designed to work with the Django template language. In the above example, we passed our ContactForm instance to the template using the context variable form. Here’s a simple example template:  ★ forms 被设计成和 django 模板语言一起工作。在上面的例子里,我们传递 contactForm 的实例给模板。

<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>

The form only outputs its own fields; it is up to you to provide the surrounding <form> tags and the submit button.

If your form includes uploaded files, be sure to include enctype="multipart/form-data" in the form element. If you wish to write a generic template that will work whether or not the form has files, you can use the is_multipart() attribute on the form:

<form action="/contact/" method="post"
    {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>

★ 当 form 包含文件时,在 form 里包含 encytpe="multipart/form-data";不管上传的是不是包含文件类型,可以使用 is_multipart() 来声明。 

Forms and Cross Site Request Forgery protection

Django ships with an easy-to-use protection against Cross Site Request Forgeries. When submitting a form via POST with CSRF protection enabled you must use the csrf_token template tag as in the preceding example. However, since CSRF protection is not directly tied to forms in templates, this tag is omitted from the following examples in this document.

form.as_p will output the form with each form field and accompanying label wrapped in a paragraph. Here’s the output for our example template:

<form action="/contact/" method="post">
<p><label for="id_subject">Subject:</label>
    <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
    <input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
    <input type="email" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
<input type="submit" value="Submit" />
</form>

Note that each form field has an ID attribute set to id_<field-name>, which is referenced by the accompanying label tag. This is important for ensuring forms are accessible to assistive technology such as screen reader software. You can also customize the way in which labels and ids are generated.

★ 生成的form field有默认的ID为 id_<field-name> , 也可以定制ID的样式。

You can also use form.as_table to output table rows (you’ll need to provide your own <table> tags) and form.as_ul to output list items.

★ 可以使用 form.as_table 或 form.as_ul 来输出不同样式 

Customizing the form template

If the default generated HTML is not to your taste, you can completely customize the way a form is presented using the Django template language. Extending the above example:  

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
    <div class="fieldWrapper">
        {{ form.message.errors }}
        <label for="id_message">Your message:</label>
        {{ form.message }}
    </div>
    <div class="fieldWrapper">
        {{ form.sender.errors }}
        <label for="id_sender">Your email address:</label>
        {{ form.sender }}
    </div>
    <div class="fieldWrapper">
        {{ form.cc_myself.errors }}
        <label for="id_cc_myself">CC yourself?</label>
        {{ form.cc_myself }}
    </div>
    <p><input type="submit" value="Send message" /></p>
</form>

 ★如果不满意默认生成的HTML,可以在用Django 模板语言定制生成的HTML。

Each named form-field can be output to the template using {{ form.name_of_field }}, which will produce the HTML needed to display the form widget. Using {{ form.name_of_field.errors }} displays a list of form errors, rendered as an unordered list. This might look like:  

★ form-field 可以用 {{ form.name_of_field }} 输出,用 {{ form.name_of_field.errors }} 输出form错误信息 

<ul class="errorlist">
    <li>Sender is required.</li>
</ul>

The list has a CSS class of errorlist to allow you to style its appearance. If you wish to further customize the display of errors you can do so by looping over them:  

★ 通过 class="errorlist" 可以定制显示的 CSS style。可以循环 errors 

{% if form.subject.errors %}
    <ol>
    {% for error in form.subject.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}

Looping over the form’s fields

If you’re using the same HTML for each of your form fields, you can reduce duplicate code by looping through each field in turn using a {% for %} loop:

<form action="/contact/" method="post">
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }} {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="Send message" /></p>
</form>

★ 在这个循环里,{{ field }}是 BoundField 的实例。以下是一些field的属性,它们非常有用。

Within this loop, {{ field }} is an instance of BoundFieldBoundField also has the following attributes, which can be useful in your templates:

{{ field.label }}
The label of the field, e.g.  Email address.    ★ field 的label 
{{ field.label_tag }}

The field’s label wrapped in the appropriate HTML <label> tag.

Changed in Django 1.6:

This includes the form’s label_suffix. For example, the default label_suffix is a colon: ★ 是 label 的前缀,默认的前缀是一个冒号 

<label for="id_email">Email address:</label>
{{ field.id_for_label }}
The ID that will be used for this field ( id_email in the example above). You may want to use this in lieu of  label_tag if you are constructing the label manually. It’s also useful, for example, if you have some inline JavaScript and want to avoid hardcoding the field’s ID.
{{ field.value }}
The value of the field. e.g  someone@example.com  ★ field 的 value,例如 someone@example.com 
{{ field.html_name }}
The name of the field that will be used in the input element’s name field. This takes the form prefix into account, if it has been set.
{{ field.help_text }}
Any help text that has been associated with the field.   ★ 和此 field 关联的 help_text 
{{ field.errors }}
Outputs a  <ul class="errorlist"> containing any validation errors corresponding to this field. You can customize the presentation of the errors with a  {% for error in field.errors %} loop. In this case, each object in the loop is a simple string containing the error message.
★ 输出 <ul class="errorlist">,包括了验证的errors。如果在loop循环中定制,那么每个输出的 loop 仅仅是一个简单的 string。
{{ field.is_hidden }}

This attribute is True if the form field is a hidden field and False otherwise. It’s not particularly useful as a template variable, but could be useful in conditional tests such as:

{% if field.is_hidden %}
   {# Do something special #}
{% endif %}
{{ field.field }}
The  Field instance from the form class that this  BoundField wraps. You can use it to access  Field attributes , e.g. {{ char_field.field.max_length }}.

Looping over hidden and visible fields

If you’re manually laying out a form in a template, as opposed to relying on Django’s default form layout, you might want to treat <input type="hidden"> fields differently than non-hidden fields. For example, because hidden fields don’t display anything, putting error messages “next to” the field could cause confusion for your users – so errors for those fields should be handled differently.

 ★ 如果你手动地在模板中设置 form 的布局,而不是使用 django 默认的 form 布局,那么,你可能会想为隐藏域 <input type="hidden"> 定义一个不同于可见域的行为。例如,隐藏域不显示任何东西,为隐藏域显示错误信息可能会使人困惑,所以,隐藏域的错误信息应该被

Django provides two methods on a form that allow you to loop over the hidden and visible fields independently: hidden_fields() and visible_fields(). Here’s a modification of an earlier example that uses these two methods:

<form action="/contact/" method="post">
    {# Include the hidden fields #}
    {% for hidden in form.hidden_fields %}
    {{ hidden }}
    {% endfor %}
    {# Include the visible fields #}
    {% for field in form.visible_fields %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }} {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="Send message" /></p>
</form>

  ★可以用不同的方法分别处理隐藏属性和非隐藏属性,它们是 hidden_fields() 和 visible_fields()。如此,则把 可见域和隐藏域区分开来。

 

This example does not handle any errors in the hidden fields. Usually, an error in a hidden field is a sign of form tampering, since normal form interaction won’t alter them. However, you could easily insert some error displays for those form errors, as well.

Reusable form templates

If your site uses the same rendering logic for forms in multiple places, you can reduce duplication by saving the form’s loop in a standalone template and using the include tag to reuse it in other templates:

<form action="/contact/" method="post">
    {% include "form_snippet.html" %}
    <p><input type="submit" value="Send message" /></p>
</form>

# In form_snippet.html:

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

★把form的循环放在独立的模板内,然后用 include 标签可以重用相同的渲染逻辑。

If the form object passed to a template has a different name within the context, you can alias it using the with argument of the include tag:

<form action="/comments/add/" method="post">
    {% include "form_snippet.html" with form=comment_form %}
    <p><input type="submit" value="Submit comment" /></p>
</form>

★在 include 语句中使用用 with 参数可以重命名。

If you find yourself doing this often, you might consider creating a custom inclusion tag.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值