Flask表单详解

news2024/12/26 22:54:09

Flask表单详解

  • 概述
  • 跨站请求伪造保护
  • 表单类
  • 把表单渲染成HTML
  • 在视图函数中处理表单
  • 重定向和用户会话
  • Flash消息

概述

尽管 Flask 的请求对象提供的信息足够用于处理 Web 表单,但有些任务很单调,而且要重复操作。比如,生成表单的 HTML 代码和验证提交的表单数据
Flask-WTF(http://pythonhosted.org/Flask-WTF/)扩展可以把处理 Web 表单的过程变成一种愉悦的体验。这个扩展对独立的 WTForms(http://wtforms.simplecodes.com)包进行了包装,方便集成到 Flask 程序中
Flask-WTF 及其依赖可使用 pip 安装:

pip install flask-wtf

跨站请求伪造保护

默认情况下,Flask-WTF 能保护所有表单免受跨站请求伪造(CSRF)的攻击
为了实现 CSRF 保护,Flask-WTF 需要程序设置一个密钥。Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

表单类

使用 Flask-WTF 时,每个 Web 表单都由一个继承自 Form 的类表示。这个类定义表单中的一组字段,每个字段都用对象表示。字段对象可附属一个或多个验证函数。验证函数用来验证用户提交的输入值是否符合要求

from flask_wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required

class NameForm(Form):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')

NameForm 表单中有一个名为 name 的文本字段和一个名为 submit 的提交按钮。StringField类表示属性为 type="text"<input> 元素。SubmitField 类表示属性为type="submit"<input> 元素

StringField 构造函数中的可选参数 validators 指定一个由验证函数组成的列表,在接受用户提交的数据之前验证数据。验证函数 DataRequired() 确保提交的字段不为空
WTForms 支持的 HTML 标准字段如下:

  1. StringField: 用于接收文本输入的字段
  2. PasswordField: 用于接收密码输入的字段
  3. TextAreaField: 多行文本输入字段
  4. IntegerField: 用于接收整数输入的字段
  5. FloatField: 用于接收浮点数输入的字段
  6. BooleanField: 用于接收布尔值输入的字段,通常表示复选框
  7. DateField: 用于接收日期输入的字段
  8. DateTimeField: 用于接收日期时间输入的字段
  9. TimeField: 用于接收时间输入的字段
  10. FileField: 用于上传文件的字段
  11. SubmitField: 提交按钮字段,用于提交表单
  12. SelectField: 下拉菜单字段,用于提供选项供用户选择
  13. RadioField: 单选按钮字段,用于提供多个选项中的一个选项供用户选择
  14. MultipleSelectField: 多选下拉菜单字段,用于提供多个选项供用户选择

支持的验证函数如下:

  • Email: 确保字段中输入的数据是合法的电子邮件地址
  • EqualTo: 确保字段中输入的数据与另一个字段中的数据相同
  • IPAddress: 确保字段中输入的数据是合法的 IP 地址
  • Length: 确保字段中输入的数据的长度在指定的范围内
  • NumberRange: 确保字段中输入的数据在指定的数字范围内
  • Optional: 表示字段可以为空,不是必需的
  • DataRequired: 确保字段中输入的数据不为空,是必需的(老的版本为Required
  • Regexp: 根据正则表达式来验证字段中输入的数据
  • URL: 确保字段中输入的数据是合法的 URL
  • AnyOf: 确保字段中输入的数据是给定列表中的一项
  • NoneOf: 确保字段中输入的数据不是给定列表中的任何一项

把表单渲染成HTML

表单字段是可调用的,在模板中调用后会渲染成 HTML

1、视图函数把一个 NameForm 实例通过参数 form 传入模板

from flask_wtf import FlaskForm

@app.route('/index')
def index():
    form = NameForm()
    return render_template('index.html', form=form)

2、在模板中可以生成一个简单的表单,如下所示

{% extends "base.html" %}

{% block title %}
Index
{% endblock %}

{% block head %}
{{ super() }}
{% endblock %}
{% block body %}
<form method="POST">
  {{ form.hidden_tag() }}
  {{ form.name.label }}
  {{ form.name() }}
  {{ form.submit() }}
</form>
{% endblock %}

在这个模板中,form.hidden_tag() 用于生成包含 CSRF 令牌的隐藏字段,以防止跨站请求伪造攻击。form.name.label 用于生成名为 name 字段的标签,用于显示在表单中。form.name() 用于生成名为 name 的输入字段,允许用户输入数据。form.submit() 用于生成提交按钮,用户点击此按钮可以提交表单

3、渲染的效果

image.png


在视图函数中处理表单

有时候我们不仅要渲染表单,还要接收表单中的数据

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

用户第一次访问程序时,服务器会收到一个没有表单数据的 GET 请求,所以 validate_on_submit() 将返回 False。if 语句的内容将被跳过,通过渲染模板处理请求,并传入表单对象和值为 None 的 name 变量作为参数。用户会看到浏览器中显示了一个表单:

在这里插入图片描述

用户提交表单后,服务器收到一个包含数据的 POST 请求。validate_on_submit() 会调用 name 字段上附属的 DataRequired() 验证函数。如果名字不为空,就能通过验证,validate_on_submit() 返回 True。现在,用户输入的名字可通过字段的 data 属性获取。在 if 语句中,把名字赋值给局部变量 name,然后再把 data 属性设为空字符串,从而清空表单字段。最后一行调用 render_template() 函数渲染模板,但这一次参数name 的值为表单中输入的名字,因此会显示一个针对该用户的欢迎消息:

在这里插入图片描述


重定向和用户会话

上述最新版的代码存在一个可用性问题。用户输入名字后提交表单,然后点击浏览器的刷新按钮,会看到一个莫名其妙的警告,要求在再次提交表单之前进行确认。之所以出现这种情况,是因为刷新页面时浏览器会重新发送之前已经发送过的最后一个请求。如果这个请求是一个包含表单数据的 POST 请求,刷新页面后会再次提交表单。大多数情况下,这并不是理想的处理方式

基于这个原因,最好别让 Web 程序把POST 请求作为浏览器发送的最后一个请求。这种需求的实现方式是,使用重定向作为 POST 请求的响应,而不是使用常规响应。重定向是一种特殊的响应,响应内容是 URL,而不是包含 HTML 代码的字符串。浏览器收到这种响应时,会向重定向的 URL 发起 GET 请求,显示页面的内容。这个页面的加载可能要多花几微秒,因为要先把第二个请求发给服务器。除此之外,用户不会察觉到有什么不同

但这种方法会带来另一个问题。程序处理 POST 请求时,使用 form.name.data 获取用户输入的名字,可是一旦这个请求结束,数据也就丢失了。因为这个 POST 请求使用重定向处理,所以程序需要保存输入的名字,这样重定向后的请求才能获得并使用这个名字,从而构建真正的响应

程序可以把数据存储在用户会话中,在请求之间“记住”数据。用户会话是一种私有存储,存在于每个连接到服务器的客户端中

@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'))

Flash消息

请求完成后,有时需要让用户知道状态发生了变化。这里可以使用确认消息、警告或者错误提醒。一个典型例子是,用户提交了有一项错误的登录表单后,服务器发回的响应重新渲染了登录表单,并在表单上面显示一个消息,提示用户用户名或密码错误

flash() 函数可实现这种效果

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
        return redirect(url_for('index'))

    return render_template('index.html', form=form, name=session.get('name'))

每次提交的名字都会和存储在用户会话中的名字进行比较,而会话中存储的名字是前一次在这个表单中提交的数据。如果两个名字不一样,就会调用 flash() 函数,在发给客户端的下一个响应中显示一个消息

仅调用 flash() 函数并不能把消息显示出来,程序使用的模板要渲染这些消息。最好在基模板中渲染 Flash 消息,因为这样所有页面都能使用这些消息

{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1636534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【stomp 实战】spring websocket用户消息发送源码分析

这一节&#xff0c;我们学习用户消息是如何发送的。 消息的分类 spring websocket将消息分为两种&#xff0c;一种是给指定的用户发送&#xff08;用户消息&#xff09;&#xff0c;一种是广播消息&#xff0c;即给所有用户发送消息。那怎么区分这两种消息呢?那就是用前缀了…

maven聚合,继承等方式

需要install安装到本地仓库&#xff0c;或者私服&#xff0c;方可使用自己封装项目 编译&#xff0c;测试&#xff0c;打包&#xff0c;安装&#xff0c;发布 parent: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://mav…

Python 机器学习 基础 之 学习 基础环境搭建

Python 机器学习 基础 之 学习 基础环境搭建 目录 Python 机器学习 基础 之 学习 基础环境搭建 一、简单介绍 二、什么是机器学习 三、python 环境的搭建 1、Python 安装包下载 2、这里以 下载 Python 3.10.9 为例 3、安装 Python 3.10.9 4、检验 python 是否安装成功&…

二分图--判定以及最大匹配

水了个圈钱杯省一&#xff0c;不过估计国赛也拿不了奖&#xff0c;但还是小小挣扎一下。 什么是二分图&#xff1a;G(V,E)是一个无向图&#xff0c;若顶点V可以分为两个互不相交的子集A,B&#xff0c;并图中的每一条边&#xff08;i,j)所关联的ij属于不同的顶点集&#xff0c;…

2024年Docker常用操作快速查询手册

目录 一、Linux系统上 Docker安装流程&#xff08;以ubuntu为例&#xff09; 一、卸载所有冲突的软件包 二、设置Docker的apt存储库&#xff08;这里使用的是阿里云软件源&#xff09; 三、直接安装最新版本的Docker 三、安装指定版本的Docker 四、验证Docker是否安装成功…

Nginx实现端口转发与负载均衡配置

前言&#xff1a;当我们的软件体系结构较为庞大的时候&#xff0c;访问量往往是巨大的&#xff0c;所以我们这里可以使用nginx的均衡负载 一、配置nginx实现端口转发 本地tomcat服务端口为8082 本地nginx端口为8080 目的&#xff1a;将nginx的8080转发到tomcat的8082端口上…

每日一题:插入区间

给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 个区间的开始和结束&#xff0c;并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval [start, end] 表示另一个区间的开始和…

【嵌入式笔试题】网络编程笔试题

非常经典的笔试题。 2.网络编程(29道) 2.1列举一下OSI协议的各种分层。说说你最熟悉的一层协议的功能。 ( 1 )七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理 层。 ( 2 )五层划分为:应用层、传输层、网络层、数据链路层、物理层。 ( 3 )…

vue 脚手架 创建vue3项目

创建项目 命令&#xff1a;vue create vue-element-plus 选择配置模式&#xff1a;手动选择模式 (上下键回车) 选择配置&#xff08;上下键空格回车&#xff09; 选择代码规范、规则检查和格式化方式: 选择语法检查方式 lint on save (保存就检查) 代码文件中有代码不符合 l…

国家开放大学2024年春《Matlab语言及其应用》实验一熟悉Matlab 操作环境参考答案

实验报告 姓名&#xff1a; 学号&#xff1a; 实验一名称&#xff1a;熟悉 Matlab 操作环境 实验目标&#xff1a;通过简单变量和矩阵的录入、计算和查看相关信息&#xff0c;了解 Matlab 操作界面 及各子窗口使用方法。熟悉一系列便于使用的 Matlab 函数和文件的工具。 实…

java-springmvc 01 补充 javaweb 三大组件Servlet,Filter、Listener(源码都是tomcat8.5项目中的)

01.JavaWeb三大组件指的是&#xff1a;Servlet、Filter、Listener,三者提供不同的功能 这三个在springmvc 运用很多 Servlet 01.Servlet接口&#xff1a; public interface Servlet {/*** 初始化方法* 实例化servlet之后&#xff0c;该方法仅调用一次 * init方法必须执行完…

【GitHub】github学生认证,在vscode中使用copilot的教程

github学生认证并使用copilot教程 写在最前面一.注册github账号1.1、注册1.2、完善你的profile 二、Github 学生认证注意事项&#xff1a;不完善的说明 三、Copilot四、在 Visual Studio Code 中安装 GitHub Copilot 扩展4.1 安装 Copilot 插件4.2 配置 Copilot 插件&#xff0…

【机器学习-19】集成学习---投票法(Voting)

一、引言 集成学习&#xff08;Ensemble Learning&#xff09;是机器学习领域中的一种重要策略&#xff0c;它通过结合多个模型的预测结果来提高整体性能。在单个模型容易过拟合或欠拟合的情况下&#xff0c;集成学习能够通过综合多个模型的优点来减少这种风险&#xff0c;从而…

ESP32 和 Arduino 之间建立蓝牙连接

ESP32 和 Arduino Uno 可以通过蓝牙进行通信。为此&#xff0c;您必须使用与 Arduino 兼容的蓝牙模块。我们将使用 HC-05&#xff08;06&#xff09; 蓝牙模块。 连接Arduino Uno和HC-05蓝牙模块 将 HC-05 蓝牙模块连接到 Arduino 板。将模块的VCC、GND、RX、TX引脚连接到Ard…

Python 与 TensorFlow2 生成式 AI(二)

原文&#xff1a;zh.annas-archive.org/md5/d06d282ea0d9c23c57f0ce31225acf76 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第四章&#xff1a;教授网络生成数字 在前一章中&#xff0c;我们涵盖了神经网络模型的构建基块。在这一章中&#xff0c;我们的第一个项目…

04 Docker练习赛从0开始到 docker 镜像提交

1.1 本地安装 docker 工具 这里以ubutun下安装docker为例,其他操作系统安装命令略有不同,可自行百度。(建议使用阿里源安装速度快) sudo apt install docker.io如果你本地有gpu,请继续执行如下命令以支持gpu调用: 注意: 英伟达对 docker 支持的 linux 发行版:https:/…

【计算智能】基本遗传算法在优化问题中的应用与实验【理论到程序】

文章目录 1. 引言&#xff1a;遗传算法简介2. 基本遗传算法&#xff08;SGA&#xff09;2.1 基本遗传算法的构成要素1. 染色体编码2. 适应度函数3. 遗传算子 2.2 实验设计与方法1. 算法流程2. 伪代码3. python实现1. 导入模块2. 目标函数 f(x)3 初始化种群4. 计算适应度5. 选择…

20232906 2023-2024-2 《网络与系统攻防技术》第七次作业

20232906 2023-2024-2 《网络与系统攻防技术》第七次作业 1.实验内容 一、使用Metasploit进行Linux远程渗透攻击 任务&#xff1a;使用Metasploit渗透测试软件&#xff0c;攻击Linux靶机上的Samba服务Usermap_script安全漏洞&#xff0c;获取目标Linux靶机的主机访问权限。实…

如何在Spring Boot中配置数据库密码加密

如何在Spring Boot中配置数据库密码加密&#xff1f; alibaba/druid Wiki GitHub 使用ConfigFilter alibaba/druid Wiki GitHub 巧用Druid数据源实现数据库连接密码的加密解密功能 import com.alibaba.druid.filter.config.ConfigTools;public class Testttt {public stat…

汽车CAN总线技术详解

1. 历史 2. 应用 3. 优点 4. 基础概念 5. 组成 6. 应用 7. 网关 8. 波形分析 参考文献 汽车CAN总线技术详解&#xff08;100多页支持下载&#xff09;