学习Flask之四、网页表单
第二章介绍的request对象,使用了客户端请求的所有信息。特别地,request.form提供了对POST请求提交的表单数据的访问。尽管Flask请求对象的支持足于处理网页单,但是还有很多作务很繁锁和重复。两个很好的例子是产生HTML表单代码和验证表单数据。
Flask-WTF扩展处理表单的体验更让人愉快。这个扩展是WTForms的 Flask集成。Flask-WTF和它的依赖可以通过pip安装:
(venv) $ pip install flask-wtf
Cross-Site Request Forgery (CSRF) 保护
黙认情况下, Flask-WTF保护所有的表单免受Cross-Site Request Forgery (CSRF)攻击。当恶意网站发送请求到攻击者登入的不同的网站时会出现CSRF攻击。
要实施 CSRF保护,Flask-WTF要求应用配置密钥。Flask-WTF用这个密钥产生加密标签来证实表单数据请求是授权的。
Example 4-1展示如何配置密钥
Example 4-1. hello.py: Flask-WTF configuration
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
app.config字典是框架、扩展或应用本身存贮配置信息的通用地方。配置值可以通过标准的字典符号添加到app.config。configuration对象也有函数从环境或文件中导入配置值。
SECRET_KEY配置变量被Flask和其它扩展用作通用密钥。如它的名字所示,加密的强度取决于变量的值。在不同的应用中使用不同的密钥并确保这个字符串不被别人知道。为了增强安全性,密钥应贮存于环境变量中而不是被嵌入到代码中。这个技术描述于第7章。
Form类
Flask-WTF时,每一个网页表单由一个类来呈现它继承自Form类。这个类定义了表单中字段的列表,每个字段呈现为一个对象。每个字段对象可以附着一个或多个验证器。验证器是检查用户输入的函数。
Example 4-2 展示一个简单的表单,它有一个文本字段和一个提交字段。
Example 4-2. hello.py: 表单类定义
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
表单中的字段以类的变量定义,每个类的变量赋一个相关的对象具有一个类型。前面的例子里,NameForm表单有一个文本字段称为name以及一个提交按钮。StringField类呈现为<input>元素具有type="text"的属性。SubmitField类呈现<input>元素具有 type="submit"属性。field构造函数的第一个参数是宣染表单时的label。
StringField 构造器中包含的可选的验证器参数定义了检查器的列表,它们在接受前作用于用户提交的数据。Required()验证器确保提效的字段非空。表单的基类被Flask-WTF 扩展定义,所以它导入自flask_wtf。但是字段和验证器自接从WTForms包导入。
WTForms支持的标准的HTML字段列表见Table 4-1.见:
http://www.aluoyun.cn/details.php?article_id=194
WTForms内在验证器的列表展示于Table 4-2. 见:
http://www.aluoyun.cn/details.php?article_id=195
表单的HTML宣染
表单字段是可调用的,即从模板宣染它们到HTML。假如view函数传递一个NameForm实例到模板作为参数,模板会产生简单的HTML表单:
<form method="POST">
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
</form>
当然结果是很粗的。要改进表单的外观,宣染字段的传入参数被转换为字段的HTML属性。
作为例子,你可以给出字段id或class属性然后定义CSS格式:
<form method="POST">
{{ form.name.label }} {{ form.name(id='my-text-field') }}
{{ form.submit() }}
</form>
但是即使具有HTML属性,用这种方法宣染表单的工作也很多,所以最好是尽可能使用Bootstrap的表单风格。
Flask-Bootstrap提供了非常高级的帮助函数来宣染Flask WTF表单,它使用Bootstrap预定义的表单式样,每个式样都有一个调用。使用Flask Bootstrap,前面的表单可以如下宣染:
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
import指令与正常的Python脚本的的作用一样并允许模板元素被导入并在许多模板中使用。 导入的bootstrap/wtf.html 文件定义帮助函数来宣染Flask-WTF表单使用Bootstrap。
wtf.quick_form()函数取Flask-WTF表单对象并宣染它用黙认的Bootstrap式样。hello.py完整的模板见Example 4-3。
Example 4-3. templates/index.html: Using Flask-WTF and Flask-Bootstrap to render a form
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}
现在模板的content区域有两个节。第一个节是网页的header展示欢迎。这里使用了模板条件。Jinja2的条件的格式为{% if variable %}...{% else %}...{% endif %}。如果条件为真,则if 与else之间的内容被宣染到模板。如果条件为假,则else和endif之间的内容被宣染。
示例的模板宣染 “Hello, Stranger!” 当name模板参数不提供时。内容的第二节宣染NameForm对象使用wtf.quick_form()函数。
View函数中处理表单
在新版的hello.py文件里,view函数index()将宣染表单并接收数据。Example 4-4展示更新的view函数index()。
Example 4-4. hello.py: Route methods
@app.route('/', methods=['GET', 'POST'])
def index():
name = None
form = NameForm()
if form.validate_on_submit():
name = form.name.data
form.name.data = ''
return render_template('index.html', form=form, name=name)
app.route装饰器中添加的方法参数告诉Flask注册view函数作为URL map中 GET 和 POST 请求的处理器。当不指定方法时,view函数只处理GET请求。
在方法列表中增加POST是必要的因为提交的表单用 POST请求更方便。也有可能用GET请求提交表单,但是GET请求没有主体,数据以查询字符串的方式附加在URL里并在浏览器的地址栏内是可见的。出于这个和其它原因,表单提交几乎都用POST请求。用局部name变量贮存接收自表单的name。当 name未知时,变量初始化为None。 view函数创建NameForm类的实例来呈现表单。
validate_on_submit()方法返回真当表单提交时,并且数据被字段验证器接收。在其它情况下,validate_on_submit()返回假。
方法的返回值确定表单是否被宣染或被处理。当用户第一次导航到应用时,服务器接收不带表单数据的GET请求,所以validate_on_submit() 返回False。if语句的主体将跳过,请求被处理通过宣染模板,它获得表单对象并将name变量设为None作为参数。用户现在可以看到浏览器中的表单。当用户提交表单时,服务器接收 POST请求的数据。validate_on_submit()调用附着于name字段的Required()验证器。如果name不是空的,则验证器接受它validate_on_submit()返回真。现在用户输入的name可以作为字段的data属性访问。在if语句的主体内,name被赋给局部变量并且 form字段被清除,通过设置数据属性为空字符串。最后一行调用的render_template()宣染模板,但是这次name参数包含来自表单的name,所以欢迎被个性化。
当用户提交name时,应用用个性化欢迎进行响应。表单还在下面,所以用户还可以提交新的name ,如果想要的话。
如果用户用空的name提交表单,Required()验证器抛出错误。注意功能是自动的。这是设计良好的Flask-WTF和Flask-Bootstrap扩展给你的应用强大的例子。
重定向和用户会话
上一版本的hello.py有个使用问题。如果你输入你的name并提交它,然后点击浏览器的刷新按钮,你会得到警告要求确认再重新提交表单。这是因为浏览器重复上一次的请求当它们请求刷新网页时。当最后一次发送POST请求使用表单数据时,刷新会导致单表的重复提交,这不是期望的行为。许多用户不理解浏览器的警告。因此,它被认为是网页应用的良好实践,不漏掉浏览器发送的最后一次POST请求。这个实践可以通过重定向响应POST请求而不是正常的请求来获得。重定向是一种特殊的响应,它有URL而不是HTML代码的字串。当浏览器接受这个响应时,它发送GET请求重定向的URL,那就是显示的页面。页面会取更长的时间来加载因为第二个请求要发送到服务器,除此之外用户不会看到别的不同。现在最后一个请求是GET,所以刷新命令如期执行。这种技巧称为Post/ Redirect/Get模式。但是这种方法有另一个问题。当应用处理POST请求时,它访问存贮于form.name.data的用户输入的name,但是请求结束时表单数据消失。因为表单数据用重定向处理,应用需要存贮 name以使重定向请求可以得到它并用它构建实际的响应。应用可以记住一个请求的东西到下一次请求通过将它们存贮在用户会话里,用户会话是私有的存贮或以被每个连接的客户端使用。
用户会话在第二章作为与请求上下文相关的变量介绍。
它调用会话并像标准的python字典一样访问。
Example 4-5 展示新版的index() view函数,它实施重定向和用户会话。
Example 4-5. hello.py: Redirects and user sessions
from flask import Flask, render_template, session, redirect, url_for
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
session['name'] = form.name.data
return redirect(url_for('index'))
return render_template('index.html', form=form, name=session.get('name'))
在上一个版本的应用中,局部变量name用于贮存用户在表单中输入的name。那个变量现在放在用户会话中,作为session['name'],以便它在请求外被记住。现在有有效表单数据的请求以调用redirect()结束, redirect()是一个产生HTTP重定向请求的帮助函数。redirect()取URL作为重定向参数。本例中的重定向URL是根URL,所以响应与redirect('/')更一致,但是实际上使用lask的URL生成函数url_for()。鼓劢使用url_for()产生URLs因为这个函数使用URL map产生URLs,所以URLs确保兼容定义的路由和任何路由名的变更可以自动获得当用这个函数时。 url_for()函数第一个和唯一要求的参数是endpoint名,每个路由拥有的内部名。黙认情况,路由的endpoint是 view函数名。本例中,处理根URL的view函数是index(),所以提供给url_for()的name参数是 index。最后的改变在 render_template()函数里,它现在从会话中直接获得name参数,使用session.get('name')。与使用正常的字典一样,使用get() 请求字典的key避免意外,对于未找到的keys,因为get()返回黙认的值None对于缺失的key。对于这个版本的应用,你可以看到刷新会得到你想要的结果。
消息推出
有时在请求完成后给用户一个状态更新是有用的。这可以是一个确认信息,警告,或错误。一个典型的例子是当你提交错误的登录表单时,服务器重新宣染登录表单并在其上面出现消息告诉你用户名或密码无效。
Flask包含了这种功能作为核心特征。Example 4-6 展示如何使用flash()函数来实现这个目的。
Example 4-6. hello.py: Flashed messages
from flask import Flask, render_template, session, redirect, url_for, flash
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
old_name = session.get('name')
if old_name is not None and old_name != form.name.data:
flash('Looks like you have changed your name!')
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html',
form = form, name = session.get('name'))
本例中,每次提交name,都与存贮在用户会话中的name比较。如果两个names不同, flash()函数被调用并显示于下一个返回客户端的响应中。
调用flash()并不足于使消息显示;应用使用的模板需要宣染这些消息。宣染推出的消息的最好的地方是基模板,因这它会在所有网页中使能这些消息。Flask有一个get_flashed_messages() 函数供模板使用以追踪消息和宣染他们,如Example 4-7所示。
Example 4-7. templates/base.html: Flash message rendering
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
{% block page_content %}{% endblock %}
</div>
{% endblock %}
本例中,消息被宣染,使用Bootstrap的CSS。
使用一个循环,因为有多个消息要显示,每次调用 flash() 都要显示。从get_flashed_messages()得到的消息不会在这个函数下一次调用时返回。所以推出的消息只显示一次然后消失。 能从网页表单接受用户数据是许多应用要求的特征,永久存贮数据也是许多应用要求的特征。下一章的主题是使用Flask的数据支持。
相关文章:
学习Flask之四、网页表单
第二章介绍的request对象,使用了客户端请求的所有信息。特别地,request.form提供了对POST请求提交的表单数据的访问。尽管Flask请求对象的支持足于处理网页单,但是还有很多作务很繁锁和重复。两个很好的例子是产生HTML表单代码和验证表单数据…...
CenterMask paper笔记
CenterMask是一个anchor free的实例分割模型, 来自paper: CenterMask: Real-Time Anchor-Free Instance Segmentation 提起anchor free, 会想到FCOS模型,是用来目标检测的, 那么这里就用到了FCOS, 不过换了backbone, 在FCOS检测出目标框后&…...
06- OpenCV查找图像轮廓 (OpenCV基础) (机器视觉)
知识重点 灰度图转换: gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)二值化: 返回两个东西,一个阈值, 一个是二值化的图: thresh, binary cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)查找轮廓: 返回两个结果,分别是轮廓和层级: c…...
OpenGL学习日记之模型绘制
自己编译运行过程中遇到的一些问题 下载Assimp已编译的lib(因为我们公司的电脑有很多权限和限制,也不能自己安装一些没有报备的软件,所以愁方便我就没有用cMake自己编译了)找到一位免费分享的博主的。 https://blog.csdn.net/lady_killer9/article/deta…...
Springboot接口多个DTO入参的Postman上传方式
在Java中使用Spring Boot框架时,可以同时使用多个DTO作为方法参数。 TO(Data Transfer Object)是一个常见的设计模式,用于封装数据传输对象。它通常用于将数据从一个层传递到另一个层,例如将数据从服务层传递到控制器…...
软考各科目考核内容详细介绍,看这里
新手在准备报考软考时,都会遇到这样的一个问题——科目这么多,我适合考什么?要想知道自己适合报什么科目,就需要了解每个科目是什么,考什么等一系列的问题。 接下来,就为大家介绍一下软考的各个科目&#…...
连续时间信号与离散时间信号
前言 《信号与系统》是一门很难的课,也是许多学校考研要考的专业课,由于每周只有两节课,所以每次上完都要及时的去复习,这里参考的教材是奥本海姆著作,刘海棠译,北京:电子工业出版社࿰…...
TPM密钥管理、使用
前面讲过证书相关内容,除了在软件方面有所应用外,在硬件方面也有很多应用。本次讲一下TPM相关的内容。 一、TPM介绍 1.1背景 TCG基于硬件安全的架构是为应对1990s后期日益增多的复杂恶意软件攻击应用而生的。当时以及现在,抵御PC客户端网络…...
return和finally执行顺序、运行时异常与一般异常异同、error和exception区别、Java异常处理机制原理与应用
文章目录1.try {}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?2.运行时异常与一般异常有何异同?3.java 程序中的错误有三种类型分别是什么4.error和exception有什么…...
我为什么放弃WinUI3
基于WinUI3开发HiNote已经有一个多月的时间了,算是做出来一个简单能用的C端软件。 基于个人的经历,说说其中的开发体验。 UI设计语言 无论是否抄袭苹果,WinUI3给人的感觉都是眼前一亮的。简洁美观,现代化,毛玻璃的美…...
2023年全国最新安全员精选真题及答案2
百分百题库提供安全员考试试题、建筑安全员考试预测题、建筑安全员ABC考试真题、安全员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 21.(单选题)静作用压路机在施工过程,要求实际含水量…...
计算机408考研先导课---C语言难点
以下为小编在重温C语言时,容易犯错的一些点,希望列出来对大家有一定帮助! 一、整型变量数的范围 类型说明符长度(字节)数的范围int4/2(有些为4字节,有些为2字节)-32768~32767short2…...
K8S 部署 Redis-Cluster 集群
本文使用 bitnami 镜像部署 redis-cluster 官方文档:https://github.com/bitnami/charts/tree/main/bitnami/redis-cluster 添加 bitnami 仓库 helm repo add bitnami https://charts.bitnami.com/bitnami自定义 values.yaml storageClass:集群的存储…...
[oeasy]python0089_大型机的衰落_Dec小型机崛起_PDP_VAX网络
编码进化 回忆上次内容 上次 回顾了 计算机存储单位的演变 最小的读写单位 是 bit 8-bit 固定下来 成为了字节(Byte) 位数容量8-bit1Byte1024Byte1 KB1024 KB1 MB1024 MB1 GB1024 GB1 TB 存储字符时 第1位 是 标志位后7位 是 ascii具体的值 可以用 1Byte 存储 计算机之间 …...
Apache Shiro与Spring Security对比
Apache Shiro VS Spring Security 1.Spring Security 官方文档:https://spring.io/projects/spring-security#overview介绍: Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spr…...
23春招-mysql事务相关高频面试题
1、什么是事务 对于一个事务,要么事务内的sql全部执行,要么都不执行 2、 事务的特性ACID 原子性 整个事务中所有的操作要么全部提交成功,要么全部失败会滚。 一致性 数据库总是从一个一致性状态转换到另一个一致性状态。假如有三个sql语句…...
天线理论知识1——基础概念介绍
基础概念介绍 文章目录 基础概念介绍前言一、主要参数二、天线的种类三、天线的测量前言 天线是用于发射和接收电磁波设备。其功能可以概括为转换自由空间中的电磁波和设备中的导行波。 一、主要参数 天线设计中要考虑的参数较多,包括 方向性函数:距离天线 r r r处的远区…...
【云原生之Docker实战】使用Docker部署StackEdit在线Markdown编辑器
【云原生之Docker实战】使用Docker部署StackEdit在线Markdown编辑器 一、StackEdit介绍1.StackEdit简介2.StackEdit中文版简介3.StackEdit中文版功能二、检查本地Docker环境1.检查系统版本2.检查系统Docker版本3.检查docker compose版本三、下载StackEdit镜像四、部署StackEdit…...
特征工程:特征构造以及时间序列特征构造
数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。由此可见,特征工程在机器学习中占有相当重要的地位。在实际应用当中,可以说特征工程是机器学习成功的关键。 那特征工程是什么? 特征工程是利用数据领域的相关…...
单master部署简要步骤
准备多台服务器,选定一台为master例如设置ip为192.168.0.10,host: k8s.master,其他分别为 k8s.s11 192.168.0.11k8s.s12 192.168.0.12....hostname可以使用命令配置hostname k8s.masterip解析可以在hosts文件中写入,如果有内部dns解析可以在内…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
