Django表单的基本使用
本文最后更新于:2 年前
若想搭建一个具备接收访问者输入功能的网站,必须理解表单,并在搭建网站时使用表单。
Form表单概述
为什么有了模型,还要自己创建表单类呢?原因之一是模型中有一些字段你不需要用户从前端输入数据,或者需要用户额外输入一些非模型字段的数据。Form表单精确控制了这些行为,相当于你在用户HTML表单输入框和Django模型之间的中间件。
Form表单的功能
自动生成HTML表单元素
检查表单数据的合法性
如果验证错误,重新显示表单(数据不会重置)
数据类型转换(字符类型的数据转换成相应的Python类型)
定义表单的方式
Django 常以 HTML 文件作为模板文件,在 HTML 文件中定义表单是实现网站交互式工作的经典方式,此外Django 也支持利用 Form 类在 Python 文件中定义表单。
Form类的常用字段
字段的通用参数
表单数据来源
表单验证
clean() 方法
调用表单实例的 clean() 方法可以对表单绑定的数据进行验证,既根据定义表单类字段时为字段设置的约束条件,如 required、unique 验证表单字段是否存在空值或重复,也可以根据字段类型验证传入的数据类型是否匹配。
若表单验证成功,验证后的数据会被存储到表单实例的 cleaned_data 属性(cleaned_data属性为 dict 类型,该属性以表单字段名为键,以字段值为元素的值)中;若验证失败则抛出ValidationError异常。
在对表单进行处理之前先对表单数据进行验证,在程序中生成并使用验证后的数据有助于提高程序的健壮性。
需要注意,表单验证完毕后,程序仍能从 request.POST 中访问到用户提交对的未验证的数据,但程序中最好使用存储在 cleaned_data中 已验证的数据。
is_valid() 方法
除了直接调用 clean() 方法对触发表单验证外,还可以调用表单实例的 is_valid() 方法,或访问表单实例的errors属性间接触发表单验证。
- 若 is_valid() 返回True,表单数据通过验证,并被存储到表单的cleaned_data属性中。
- 若 is_valid() 返回 False,说明表单数据未能通过验证。表单实例的errors属性在第一次被访问时可以触发表单验证。
实例化、处理和渲染表单
在模板中渲染表单实例与渲染模型实例基本相同,但存在一些关键性的差异:模型实例若为空,模板对它进行的处理没有意义;但表单实例为空时,模板需要将其渲染为空表单,以便用户填充数据。
基于以上差异,处理模型时,一般从数据库中获取实例;在代码中处理表单时,则需在视图中实例化表单。我们可以在视图中实例化一个空表单,也可以预先准备数据,实例化一个非空表单。
1. 编写表单类
我们可以通过 Django 提供的 Form 类来自用生成页面上的表单,不再需要手动在HTML中编写,最终由框架将 Django 表单渲染成真正的HTML元素。
在当前 app 内新建一个forms.py
文件(这个套路是Django的惯用手法,就像views.py
,models.py
等等),然后输入下面的内容:
1 |
|
说明:
- 提前导入forms模块
- 所有的表单类都要继承forms.Form类
- label 用于设置说明标签,相当于 name 属性。
- 每个表单字段都有自己的字段类型比如 CharField,它们分别对应一种HTML语言中的
<form>
元素中的表单元素。这一点和 Django 模型系统的设计非常相似。 max_length
限制最大长度为100。它同时起到两个作用,一是在浏览器页面限制用户输入不可超过100个字符,二是在后端服务器验证用户输入的长度不可超过100。
2. 视图处理
需要在视图中,实例化我们编写好的表单类:
1 |
|
处理表单时只会涉及 GET 和 POST 两种 HTTP 请求方式,以上视图被调用后首先判断请求方式,若接收了GET请求,则创建一个空的表单实例,将其放在模板上下文中进行渲染;若接收了POST请求,则使用POST请求中携带的数据实例化一个非空表单。
要点:
- 对于 GET 方法请求页面时,返回空的表单,让用户可以填入数据;
- 对于 POST 方法,接收表单数据,并验证;
- 如果数据合法,按照正常业务逻辑继续执行下去;
- 如果不合法,返回一个包含先前数据的表单给前端页面,方便用户修改。
- 千万要注意最后一行return语句的缩进位置。
- 每个Django表单的实例都有一个内置的
is_valid()
方法,用来验证接收的数据是否合法。如果所有数据都合法,那么该方法将返回 True,并将所有的表单数据转存到它的一个叫做cleaned_data
的属性中,该属性是一个字典类型数据。若验证失败则抛出ValidationError异常。
3. 模板处理
在 Django 的模板中,我们只需要按下面处理,就可以得到完整的HTML页面:
1 |
|
要点:
<form>...</form>
标签要自己写;- 使用 POST 的方法时,必须添加
{% csrf_token %}
标签,用于处理csrf安全机制; {{ form }}
代表Django为你生成其它所有的form标签元素,也就是我们上面做的事情;- 提交按钮需要手动添加!
4. 效果测试
表单模板
表单渲染格式
Django 在将表单字段渲染为 HTML 代码时不会为其添加标签,开发人员需要主动在模板中的表单外添加标签。若表单中的每个字段都需要添加标签,开发人员需遍历表单,逐个获取表单字段并添加标签,此项操作非常繁琐。
Django 提供了3个可选的表单渲染选项:as_table、as_p、as_ul,开发人员可利用它们简捷地实现上述功能。
{{ form.as_table }}
将表单渲染成一个表格元素,每个输入框作为一个<tr>
标签。{{ form.as_p }}
将表单的每个输入框包裹在一个<p>
标签内 tags。{{ form.as_ul }}
将表单渲染成一个列表元素,每个输入框作为一个<li>
标签。
注意:你要自己手动编写
<table>
和<ul>
标签。
手动渲染表单字段
直接 {{ form }}
虽然好,啥都不用操心,但是往往并不是你想要的,比如你要使用CSS和JS,或者字段之间添加其他元素,这些都需要对表单内的 input 元素进行额外控制,那怎么办呢?配合模板标签手动渲染字段就可以了。
根据模型创建表单
如果需要构建一个由数据库驱动的应用程序,那么很可能会用到与 Django 模型密切相关的表单。例如我们在前面的章节中定义了商品模型类 Goods,并实现了基于表单类的商品管理,但为表单定义字段类型是多余的,因为表单可以直接使用已在模型中定义的字段。
自定义模型表单类
自定义的模型表单类时需要继承 ModelForm类,ModelForm定义在 django.forms 模块中。
1 |
|
若在表单类中重新定义了模型中的字段,表单字段将会覆盖模型字段。
模型表单类的字段
在定义基于模型的表单时可以选择模型中的部分字段作为表单字段,或排除部分不需要在表单中出现的模型字段。
无论使用哪一种方式选择字段,字段会按模型中定义的顺序在表单中出现,ManyToManyField 会排在最后。
基于模型生成表单类时,Django会按照表单中内部类 Meta 中的 fields 属性指定的顺序为每个指定的模型字段定义一个表单字段:
模型字段 | 表单字段 |
---|---|
AutoField | 不呈现在表单中 |
BooleanField | 若该字段的参数null=True,该字段对应NullBooleanField,否则对应BooleanField。 |
CharField | CharField 将 max_length 设置为模型字段的 max_length ,如果模型中设置了 null=True ,会将 empty_value 设置为 None 。 |
DateField | DateField |
DateTimeField | DateTimeField |
DecimalField | DecimalField |
EmailField | EmailField |
FileField | FileField |
ForeignKey | ModelChoiceField |
ImageField | ImageField |
IntegerField | IntegerField |
ManyToManyField | ModelMultipleChoiceField |
SmallIntegerField | IntegerField |
TextField | CharField,且设置 widget=forms.Textarea |
在利用模型定义表单类时,表单字段参数的取值会受到模型字段参数取值的影响:
使用模型表单类
模型表单类的使用与表单类基本相同,创建表单模型类GoodForm的实例。
1 |
|
我们可以在实例化时为 GoodForm 传入模型实例,获得一个填充了数据的表单:
下面利用前面自定义的表单类,编写视图函数,修改商品信息:
1 |
|
模板页面渲染表单:
1 |
|
配置路由:
1 |
|
最终页面测试效果:
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!