Django——form模块
文章目录
官方文档
一、HTML表单
在HTML中,表单是在 <form>...</form>
中的一些元素,它允许访客做一些类似输入文本、选择选项、操作对象或空间等动作,然后发送这些信息到服务端。
一些表单界面元素(文本框或复选框)内置在HTML中。其他会更复杂些;像弹出日期选择或者允许您移动滑块或者操作控件,一般通过使用JavaScript,CSS以及HTML表单中的 <input>
元素来实现这些效果。
和它的元素 <input>
一样,表单必须指定两样东西:
- 何地:负责响应用户输入数据的URL地址
- 如何:数据请求使用的HTTP方法。
例如,Django admin的登录表单包含了一些 <input>
元素:用户名用 type="text"
,密码用 type="password"
,登录按钮用 type="submit"
。它还包含一些用户看不到的隐藏文本字段,Django用它们来决定下一步行为。
它还告诉浏览器表单数据应该发往 <form>
的 action
属性指定的URL—— /admin/
,并且应该使用它的 method
属性指定的HTTP方法—— post
。
当 <input type="submit" value="Log in">
元素被触发的时候,数据会发送到 /admin/
。
1.GET和 POST
处理表单时只会用到 GET
和 POST
两种HTTP方法。
Django的登录表单使用 POST
方法传输数据,在这个方法中浏览器会封装表单数据,为了传输会进行编码,然后发送到服务端并接收它的响应。
相比之下,GET
方法将提交的数据捆绑到一个字符串中,并用它来组成一个URL。该URL包含了数据要发送的地址以及一些键值对应的数据。如果您在Django文档中进行一次搜索,就会看到这点,它会生成一个形似 https://docs.djangoproject.com/search/?q=forms&release=1
的URL。
GET
和 POST
通常用于不同的目的。
任何可能用于更改系统状态的请求应该使用 POST
—— 比如一个更改数据库的请求。GET
应该只被用于不会影响系统状态的请求。
GET
方法也不适合密码表单,因为密码会出现在URL中,于是也会出现在浏览器的历史记录以及服务器的日志中,而且都是以纯文本的形式。它也不适合处理大量的数据或者二进制数据,比如一张图片。在WEB应用的管理表单中使用 GET
请求具有安全隐患:攻击者很容易通过模拟请求来访问系统的敏感数据。 POST
方法通过与其他像Django的 CSRF protection 这样的保护措施配合使用,能对访问提供更多的控制。
另一方面, GET
方法适用于诸如网页搜索表单这样的内容,因为这类呈现为一个 GET
请求的URL很容易被存为书签、分享或重新提交。
二、Django在表单中的角色
处理表单是一件挺复杂的事情。想想看Django的admin,许多不同类型的数据可能需要在一张表单中准备显示,渲染成HTML,使用方便的界面进行编辑,传到服务器,验证和清理数据,然后保存或跳过进行下一步处理。
Django的表单功能可以简化和自动化上述工作的大部分内容,并且也能比大多数程序员自己编写代码去实现来的更安全些。
Django会处理涉及表单的三个不同部分:
- 准备并重组数据,以便下一步的渲染
- 为数据创建HTML 表单
- 接收并处理客户端提交的表单及数据
三、Django 中的表单
我们已经简单的描述过了HTML 表单,但是一个HTML <form>
只是其所需的一部分。
Web应用中所说的’表单’,可能指的是HTML <form>
,或者是生成了它的Django,再或者是提交时返回的结构化数据,亦或是这些端到端作业的合集。
1. Django的Form类
Django表单系统的核心组件是Form
类。它与Django模型描述对象的逻辑结构、行为以及它呈现给我们内容的形式的方式大致相同,Form
类描述一张表单并决定它如何工作及呈现。
类似于模型类的字段映射到数据库字段的方式,表单类的字段会映射到HTML表单的 <input>
元素。ModelForm
通过Form
映射模型类的字段到HTML表单的 <input>
元素,Django admin就基于此。
表单字段本身也是类;他们管理表单数据并在提交表单时执行验证。DateField
和FileField
处理的数据类型差别很大,所以必须用来处理不同的字段。
在浏览器中,表单字段以HTML“控件”(用户界面的一个片段)的形式展现给我们。每个字段类型都有与之相匹配的控件类 ,但必要时可以覆盖。
2. 实例化、处理和渲染表单
在Django中渲染一个对象的时候,我们通常:
- 在视图中获取它(例如从数据库中取出)
- 将它传递给模板上下文
- 使用模板变量将它扩展为HTML标记
在模板中渲染表单几乎与渲染任何其他类型的对象的一样,但是存在一些关键性的差异。
如果模型实例不包含数据,在模板中对它做任何处理几乎没什么用。但完全有理由用来渲染一张空表单——当我们希望用户来填充的时候就会这么做。
所以当我们在视图中处理模型实例时,我们一般从数据库中获取它。当我们处理表单时,我们一般在视图中实例化它。
当我们实例化表单时,我们可以选择让它为空或者对它预先填充,例如使用:
- 来自已保存的模型实例的数据(例如在管理编辑表单的情况下)
- 我们从其他来源获取的数据
- 从前面一个HTML 表单提交过来的数据
最后一种情况最有趣,因为这使得用户不仅可以阅读网站,而且还可以将信息发回给它。
四、详解Django Form
类
所有表单类都作为django.forms.Form
或者django.forms.ModelForm
的子类来创建。您可以把 ModelForm
想象成 Form
的子类。实际上 Form
和 ModelForm
从(私有) BaseForm
类继承了通用功能,但是这个实现细节不怎么重要。
1. 绑定的和未绑定的表单实例
- 未绑定的表单没有与其关联的数据。当渲染给用户的时候,它会是空的或者包含默认值。
- 绑定的表单拥有已提交的数据,因此可以用来判断数据是否合法。如果渲染了一张非法的绑定的表单,它将包含内联的错误信息,告知用户要纠正哪些数据。
表单的is_bound
属性将告诉您一张表单是否具有绑定的数据。
2.字段详解
考虑一下比我们上面的小示例更有用的一张表单,我们可以用它在个人网站上实现“联系我”的功能:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
在这个例子中,我们的表单有四个字段: subject
、 message
、 sender
和 cc_myself
。只用到三种可用的字段类型:CharField
、EmailField
和BooleanField
;完整的字段类型清单请参看 表单字段 。
2-1 控件
每个表单字段都有一个相对应的控件类 ,这个控件类又有对应的HTML表单控件,比如 <input type="text">
。
多数情况下,字段都有合适的默认控件。比如,默认情况下,CharField
有个TextInput
控件,它会在HTML中生成一个 <input type="text">
。如果您想要的是 <textarea>
,您要在定义表单字段的时候指定控件,就像我们对 ``message` 字段那样处理。
2-2 字段数据
无论用表单提交了什么数据,一旦通过调用 is_valid()
验证成功( is_valid()
返回 True
),已验证的表单数据将被放到 form.cleaned_data
字典中。这里的数据已经很好的为你转化为Python类型。
注:
此时您依然能够直接从
request.POST
中访问到未验证的数据,但最好还是使用经验证的数据。
在上面的联系表单示例中, cc_myself
会被转化成一个布尔值。同样的,字段IntegerField
和FloatField
的值分别会被转化为Python的 int
和 float
类型。
有些字段类型需要一些额外的处理。例如,使用表单上传文件就要以不同的方式处理(它们可以从 request.FILES
获取,而不是 request.POST
中)。
五、使用表单模板
您只需将表单实例放到模板的上下文中即可。因此,如果您的表单在上下文中叫 form
,那么 {
{ form }}
将渲染它相应的 <label>
和 <input>
元素。
1. 表单渲染选项
额外表单模板标签
不要忘记,一张表单的输出 不 包含外层
<form>
标签以及submit
控件。这些必须由你自己提供。
对于 <label>
/