第四章:Django表单 - 1:使用表单
假设你想从表单接收用户名数据,一般情况下,你需要在HTML中手动编写一个如下的表单元素:
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>
<form action="/your-name/" method="post">
这一行定义了我们的发送目的地/your-name/
和HTTP方法POST
。form元素内部还定义了一个说明标签<label>
和一个发送按钮‘submit’,以及最关键的接收用户输入的<input>
元素。具体的更多HTML语言相关内容,请自行学习。
一、编写表单类
我们可以通过Django提供的Form类来自用生成上面的表单,不再需要手动在HTML中编写。
首先,在你当前app内新建一个forms.py
文件(这个套路是Django的惯用手法,就像views.py
,models.py
等等),然后输入下面的内容:
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
要点:
- 提前导入forms模块
- 所有的表单类都要继承forms.Form类
- 每个表单字段都有自己的字段类型比如CharField,它们分别对应一种HTML语言中的
<form>
元素中的表单元素。这一点和Django模型系统的设计非常相似。 - 例子中的label用于设置说明标签
max_length
限制最大长度为100。它同时起到两个作用,一是在浏览器页面限制用户输入不可超过100个字符,二是在后端服务器验证用户输入的长度不可超过100。
(警告:由于浏览器页面是可以被篡改、伪造、禁用、跳过的,所有的HTML手段的数据验证只能防止意外不能防止恶意行为,是没有安全保证的,破坏分子完全可以跳过浏览器的防御手段伪造发送请求!所以,在服务器后端,必须将前端当做“裸机”来对待,再次进行完全彻底的数据验证和安全防护!)
每个Django表单的实例都有一个内置的is_valid()
方法,用来验证接收的数据是否合法。如果所有数据都合法,那么该方法将返回True,并将所有的表单数据转存到它的一个叫做cleaned_data
的属性中,该属性是一个字典类型数据。
当我们将上面的表单渲染成真正的HTML元素,其内容如下:
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100" required />
一定要注意,它不包含
标签本身以及提交按钮!!!为什么要这样?方便你自己控制表单动作和CSS,JS以及其它类似bootstrap框架的嵌入!
二、视图处理
需要在视图中,实例化我们编写好的表单类。
# views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# 如果form通过POST方法发送数据
if request.method == 'POST':
# 接受request.POST参数构造form类的实例
form = NameForm(request.POST)
# 验证数据是否合法
if form.is_valid():
# 处理form.cleaned_data中的数据
# ...
# 重定向到一个新的URL
return HttpResponseRedirect('/thanks/')
# 如果是通过GET方法请求数据,返回一个空的表单
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
要点是:
- 对于GET方法请求页面时,返回空的表单,让用户可以填入数据;
- 对于POST方法,接收表单数据,并验证;
- 如果数据合法,按照正常业务逻辑继续执行下去;
- 如果不合法,返回一个包含先前数据的表单给前端页面,方便用户修改。
通过表单的is_bound
属性可以获知一个表单已经绑定了数据,还是一个空表。
三、模板处理
在Django的模板中,我们只需要按下面处理,就可以得到完整的HTML页面:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
要点:
<form>...</form>
标签要自己写;- 使用POST的方法时,必须添加
{% csrf_token %}
标签,用于处理csrf安全机制; {{ form }}
代表Django为你生成其它所有的form标签元素,也就是我们上面做的事情;- 提交按钮需要手动添加!
提示:默认情况下,Django支持HTML5的表单验证功能,比如邮箱地址验证、必填项目验证等等。
四、高级技巧
上面的例子中,只有一个用户名输入框,太简单了,实际上有更多的表单元素。看下面的例子:
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)
这个例子就有4个框组了。实际上Django的表单模块为我们内置了许多表单字段,如下所示:
- BooleanField
- CharField
- ChoiceField
- TypedChoiceField
- DateField
- DateTimeField
- DecimalField
- DurationField
- EmailField
- FileField
- FilePathField
- FloatField
- ImageField
- IntegerField
- GenericIPAddressField
- MultipleChoiceField
- TypedMultipleChoiceField
- NullBooleanField
- RegexField
- SlugField
- TimeField
- URLField
- UUIDField
- ComboField
- MultiValueField
- SplitDateTimeField
- ModelChoiceField
- ModelMultipleChoiceField
每一个表单字段类型都对应一种Widget类,每一种Widget类都对应了HMTL语言中的一种input元素类型,比如<input type="text">
。需要在HTML中实际使用什么类型的input,就需要在Django的表单字段中选择相应的field。比如要一个<input type="text">
,可以选择一个CharField
。
一旦你的表单接收数据并验证通过了,那么就可以从form.cleaned_data
字典中读取所有的表单数据,下面是一个例子:
# views.py
from django.core.mail import send_mail
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)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
五、 使用表单模板
1.表单渲染格式
前面我们通过{{ form }}
模板语言,简单地将表单渲染到HTML页面中了,实际上,有更多的方式:
{{ form.as_table }}
将表单渲染成一个表格元素,每个输入框作为一个<tr>
标签{{ form.as_p }}
将表单的每个输入框包裹在一个<p>
标签内 tags{{ form.as_ul }}
将表单渲染成一个列表元素,每个输入框作为一个<li>
标签
注意:你要自己手动编写<table>
和<ul>
标签。
下面是将上面的ContactForm作为{{ form.as_p }}
的例子:
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required /></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
注意:Django自动为每个input元素设置了一个id名称,对应label的for参数。
2.手动渲染表单字段
直接{{ form }}
虽然好,啥都不用操心,但是往往并不是你想要的,比如你要使用CSS和JS,比如你要引入Bootstarps框架,这些都需要对表单内的input元素进行额外控制,那怎么办呢?手动渲染字段就可以了。
可以通过{{ form.name_of_field }}
获取每一个字段,然后分别渲染,如下例所示:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
其中的label标签甚至可以用label_tag()
方法来生成,于是可以简写成下面的样子:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
这样子是不是更加灵活了呢?但是灵活的代价就是我们要写更多的代码,又偏向原生的HTML代码多了一点。
3. 渲染表单错误信息:
注意上面的例子中,我们使用{{ form.name_of_field.errors }}
模板语法,在表单里处理错误信息。对于每一个表单字段的错误,它其实会实际生成一个无序列表,参考下面的样子:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
这个列表有个默认的CSS样式类errorlist
,如果你想进一步定制这个样式,可以循环错误列表里的内容,然后单独设置样式:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
一切非字段的错误信息,比如表单的错误,隐藏字段的错误都保存在{{ form.non_field_errors }}
中,上面的例子,我们把它放在了表单的外围上面,它将被按下面的HTML和CSS格式渲染:
<ul class="errorlist nonfield">
<li>Generic validation error</li>
</ul>
4. 循环表单的字段:
如果你的表单字段有相同格式的HMTL表现,那么完全可以循环生成,不必要手动的编写每个字段,减少冗余和重复代码,只需要使用模板语言中的{% for %}
循环,如下所示:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
下表是{{ field }}
中非常有用的属性,这些都是Django内置的模板语言给我们提供的方便:
属性 | 说明 |
---|---|
{{ field.label }} |
字段对应的label信息 |
{{ field.label_tag }} |
自动生成字段的label标签,注意与{{ field.label }} 的区别。 |
{{ field.id_for_label }} |
自定义字段标签的id |
{{ field.value }} |
当前字段的值,比如一个Email字段的值someone@example.com |
{{ field.html_name }} |
指定字段生成的input标签中name属性的值 |
{{ field.help_text }} |
字段的帮助信息 |
{{ field.errors }} |
包含错误信息的元素 |
{{ field.is_hidden }} |
用于判断当前字段是否为隐藏的字段,如果是,返回True |
{{ field.field }} |
返回字段的参数列表。例如{{ char_field.field.max_length }} |
5. 不可见字段的特殊处理:
很多时候,我们的表单中会有一些隐藏的不可见的字段,比如honeypot。我们需要让它在任何时候都仿佛不存在一般,比如有错误的时候,如果你在页面上显示了不可见字段的错误信息,那么用户会很迷惑,这是哪来的呢?所以,通常我们是不显示不可见字段的错误信息的。
Django提供了两种独立的方法,用于循环那些不可见的和可见的字段,hidden_fields()
和visible_fields()
。这里,我们可以稍微修改一下前面的例子:
{# 循环那些不可见的字段 #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# 循环可见的字段 #}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
6. 重用表单模板
如果你在自己的HTML文件中,多次使用同一种表单模板,那么你完全可以把表单模板存成一个独立的HTML文件,然后在别的HTML文件中通过include模板语法将其包含进来,如下例所示:
# 实际的页面文件中:
{% include "form_snippet.html" %}
-----------------------------------------------------
# 单独的表单模板文件form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
如果你的页面同时引用了好几个不同的表单模板,那么为了防止冲突,你可以使用with参数,给每个表单模板取个别名,如下所示:
{% include "form_snippet.html" with form=comment_form %}
在使用的时候就是:
{% for field in comment_form %}
......
如果你经常做这些重用的工作,建议你考虑自定义一个内联标签,这已经是Django最高级的用法了。
第四章:Django表单 - 1:使用表单的更多相关文章
- Windows PE 第四章 导入表
第四章 导入表 导入表是PE数据组织中的一个很重要的组成部分,它是为实现代码重用而设置的.通过分析导入表数据,可以获得诸如OE文件的指令中调用了多少外来函数,以及这些外来函数都存在于哪些动态链接库里等 ...
- 第四章 Web表单
4.1 跨站请求伪造保护 安装flask-wtf app = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string' 密钥不 ...
- Django表单介绍
HTML 表单 在HTML中,表单是<form>...</form> 之间元素的集合,它们允许访问者输入文本.选择选项.操作对象和控制等等,然后将信息发送回服务器. 某些表单的 ...
- 第四章:Django表单 - 2:Django表单API详解
声明:以下的Form.表单等术语都指的的广义的Django表单. Form要么是绑定了数据的,要么是未绑定数据的. 如果是绑定的,那么它能够验证数据,并渲染表单及其数据,然后生成HTML表单.如果未绑 ...
- 第四章:Django表单 - 3:Django表单字段汇总
Field.clean(value)[source] 虽然表单字段的Field类主要使用在Form类中,但也可以直接实例化它们来使用,以便更好地了解它们是如何工作的.每个Field的实例都有一个cle ...
- 第二十二章 Django会话与表单验证
第二十二章 Django会话与表单验证 第一课 模板回顾 1.基本操作 def func(req): return render(req,'index.html',{'val':[1,2,3...]} ...
- ASP.NET Core 中文文档 第四章 MVC(3.4)如何使用表单
原文:Working with Forms 作者:Rick Anderson.Dave Paquette.Jerrie Pelser 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) 这篇文章演示了 ...
- KnockoutJS 3.X API 第四章 表单绑定(11) options绑定
目的 options绑定主要用于下拉列表中(即<select>元素)或多选列表(例如,<select size='6'>).此绑定不能与除<select>元素之外的 ...
- 深入浅出ExtJS 第四章 表单与输入控件
4.1 制作表单 var form = new Ext.form.FormPanel({ title:'form', defaultType:'textfield', buttonAlign:'cen ...
随机推荐
- 2022DASCTF Apr X FATE 防疫挑战赛-- SimpleFlow
1.SimpleFlow 得到pcapng文件,协议分级统计显示大部分为TCP流和http流 过滤http流,发现了flag.zip,foremost分离,得到加密的zip 在pcapng中寻找pas ...
- 沁恒CH32V103C8T6(二): Linux RISC-V编译和烧录环境配置
目录 沁恒CH32V103C8T6(一): 核心板焊接和Windows开发环境配置 沁恒CH32V103C8T6(二): Linux RISC-V编译和烧录环境配置 硬件准备 CH32V103 开发板 ...
- EF Core 数据过滤
1 前言 本文致力于将一种动态数据过滤的方案描述出来(基于 EF Core 官方的数据筛选器),实现自动注册,多个条件过滤,单条件禁用(实际上是参考ABP的源码),并尽量让代码保持 EF Core 的 ...
- TCP协议调试工具TcpEngine V1.3.0使用教程
简介 这里说的TCP协议调试定义是在开发长连接TCP协议应用时,为了验证代码流程或查找bug,需要与对端交互数据过来,当需要时可以暂停发送:单条发送:跳过发送:正常发送:发送时修改数据等. T ...
- 浮点数(UVa11809)题解
浮点数(UVa11809)题解 如题 计算机常用阶码-尾数的形式保存浮点数.如下所示,若阶码有6位,尾数有8位,可以表达的最大的浮点数为0.1111111112 * 2 ^ 1111112.注意小数点 ...
- qbxt五一数学Day3
目录 1. 组合数取模 1. \(n,m\le 200\),\(p\) 任意 2. \(n,m\le 10^6\),\(p\ge 10^9\) 素数 3. \(n,m\le 10^6\),\(p\le ...
- 初识Sentinel--雪崩问题及其解决方法
什么是雪崩问题? 雪崩问题:微服务调用链中的某个服务故障,引起整个链路中的所有微服务不可用. 解决雪崩问题的常见四种方式: ①超时处理:设定超时时长,请求超过一定时间没有响应就返回错误信息,不会无休止 ...
- 从零开始Blazor Server(7)--使用Furion权限验证
序 上面两篇我们讲了怎么用OnNavigateAsync来验证权限,又写了怎么用策略来验证权限. 其实我们既然集成了Fution,就可以用Furion带的方式来验证. 创建AdminHandler 我 ...
- Java基础 | Stream流原理与用法总结
Stream简化元素计算: 一.接口设计 从Java1.8开始提出了Stream流的概念,侧重对于源数据计算能力的封装,并且支持序列与并行两种操作方式:依旧先看核心接口的设计: BaseStream: ...
- 如何成为一名合格的Apache项目Committer,参与Apache开源贡献的正确姿势
近日,孙金城老师在 "Open Source Promotion Plan - Summer 2020" 开源软件供应链点亮计划做了<如何成为一名合格的Apache项目Com ...