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:

  1. Display an HTML form with automatically generated form widgets.
  2. Check submitted data against a set of validation rules.
  3. Redisplay a form in the case of validation errors.
  4. Convert submitted form data to the relevant Python data types.

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.
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.
Form Media
The CSS and JavaScript resources that are required to render a form.

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).

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包含了fields和校验的规则, 编写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 andcc_myselfCharFieldEmailField and BooleanField are just three of the available field types; a full list can be found in 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在django的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...
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的两种状态:未绑定和绑定

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.

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

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.

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 ourContactForm instance to the template using the context variable form. Here’s a simple example template:

<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 formelement. 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 %}>

★不管上传的是不是文件类型使用 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="text" 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) andform.as_ul to output list items.

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:

<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:

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

★循环输出errors可以定制如何显示错误信息。

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_tag }}
The field’s label wrapped in the appropriate HTML <label> tag, e.g.<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.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.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.
{{ 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 Fieldattributes , 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.

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 thewith 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.

读 Working with forms 一些心得的更多相关文章

  1. 读php手册一点点心得(1)

    1.   要输出大段文本时,跳出PHP解析模式通常比将文本通过echo或print输出更有效率(手册) 2.   note :为了代码的发行及一致性,确保不要使用短标记,短标记仅通过php.ini配置 ...

  2. buaaoo_second_assignment

    远瞧忽忽悠悠,近瞧飘飘摇摇,走近点留神看,原来是,电梯被测爆 (一)基于多线程的设计分析 (1)傻瓜电梯 第一次电梯本来想用多线程去写,但是当时对于线程的理解还不够充分(甚至把人当成了线程去找电梯,然 ...

  3. 关于UWB技术:DecaWave公司的DW1000芯片资料

    关于人在隧道工作时都需要准确的精确度确定精准的位置.DecaWave公司的DW1000芯片,对定位上的精确度更是再适合不过了.符合IEEE802.15.4-2011超宽带标准.按照数据手册上应该最小误 ...

  4. OKR案例——不同类型的OKR实例

    OKR是一种能将团队调动起来一起向着一个方向去努力的绝佳目标管理法,它让我们的团队去挑战自己的极限,去实现更大的价值,去将我们的战略最完美的转化为成果. 然而,想要让OKR在我们的团队中发挥作用,制定 ...

  5. 从心出发-刷leetcode写给5年后的自己

    而立之年终未立,不惑而年犹存惑!这或许就是所谓的中年危机吧! 自认为是一个"勤奋"的人,又"未有寸功",天天碌碌,不知何为. "常立志"而未 ...

  6. 基于UWB技术的DW1000芯片简单解析

    近些年来随着物联网和机器人技术的大发展,精确定位技术的热度也随之攀升.目前精确定位的技术有很多,如基于wifi.RFID.zigbee.超声波.UWB等技术都可以实现精准定位.由于技术的不同,精度也不 ...

  7. 漫谈碎片化学习(Fragmentation learning)

    碎片化学习(Fragmentation Learning) 从一个互联网小段子讲起: 某天,美国情报部门FBI应奥巴马的要求,做相关汇报:“报告总统,经FBI分析,中国‘短信’中35%是节日祝福语,2 ...

  8. 关于多本小说站的SEO—从”易读中文网”获得的心得体会

    从目前国内的网站流量来说,电影站,小说站,游戏站等的流量占总流量的比例还是很高的,许多站长把目光投入到了这几个方面,本文就着重来说对于小说站,尤其是多本小说站的SEO心得体会! 对于小说站来说,只要排 ...

  9. 入坑机器学习?听听MIT在读博士的AI心得

    随着人工智能技术的火热,越来越多的年轻学者正准备投身其中,开启自己的研究之路.和所有其他学科一样,人工智能领域的新人总会遇到各种各样的难题,其中不仅有研究上的,也有生活方面的.MIT EECS 在读博 ...

随机推荐

  1. axure母版(模板)区域介绍

    axure的模板区域是非常重要的一个功能,网站的头部.尾部部分等很多页面同时用到的内容,都可以使用母版,因为在母版中只需要修改一次,就可以实现所有的页面更新,可以大大的加速原型的制作速度.需要重复理解 ...

  2. psl/sql本地与远程连接配置

    一:下载Oracleclient 下载地址:http://www.oracle.com/technetwork/database/features/instant-client/index-09748 ...

  3. appium 真机测试问题 出现 instruments crashed on startup

    1.appium 真机测试的时候 instruments crashed on startup,必须在真机上打开UI Automation 在设置里: Developer->Enable UI ...

  4. v$lock 视图访问慢解决方法

    V$ 视图访问慢 --解决方法 分析:可能是有数据字典统计信息过久,造成. exec dbms_stats.gather_fixed_objects_stats; ------收集所有数据字典的fix ...

  5. 工信部表态支持Linux,可是Linux又是什么呢?

    近日,工信部高层官员出面表态:工信部大力支持发展国产Linux操作系统,可是,Linux又是什么呢?假设依照工信部的说法,发展所谓"国产Linux".恐怕要给国家带来麻烦. 大家知 ...

  6. U3D——Unity3D的脚本-script入门

     Unity3D的基本操作非常easy就能掌握了,接下来就是游戏系统的核心部分:脚本. 什么是Script(脚本)?简而言之,就是使用代码来运行一系列动作命令的特殊文本,它须要编译器来从新解读.U ...

  7. Microsoft JET Database Engine 错误 '80004005'不是一个有效的路径。 确定路径名称拼写是否正确,以及是否连接到文件存放的服务器。

  8. svn跨机备份

    #!/bin/sh svn_bak_dir='/svndata/cloudil' svn_server='svn://172.16.40.200:9999' user=adminread pass=a ...

  9. 枚举类型互相转换(使用GetEnumName和TypeInfo两个函数)

    usesClasses,TypInfo ; typeTCommandType = (ctEmptyCommand,ctAdd,ctModify); TCommandTypeConvert=classp ...

  10. vim高级编辑(一)

    本文出自   http://blog.csdn.net/shuangde800 ------------------------------------------------------------ ...