作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
网页表单,如文本字段和文本区域,让用户能够将数据发送到应用程序,无论是下载或无线电按钮,该应用程序将使用执行一个操作,或发送大量的文本区域进行处理或显示,例如,在社交媒体应用程序中,您可能给用户一个框,他们可以将新内容添加到他们的页面。
Flask是一个轻量级的Python网页框架,提供用于在Python语言中创建网页应用程序的有用的工具和功能。为了在Flask中以安全和灵活的方式渲染和验证网页表单,您将使用Flask-WTF(https://flask-wtf.readthedocs.io/en/1.0.x/),这是一个Flask扩展,可帮助您在Flask应用程序中使用WTForms库。
WTForms是一个 Python 库,提供灵活的 Web 表单渲染。 您可以使用它来渲染文本字段、文本区域、密码字段、无线电按钮等。 WTForms 还提供使用不同的 validators 进行强大的数据验证,以验证用户提交的数据符合您定义的某些标准。 例如,如果您有所需的字段,您可以确保用户提交的数据提供,或具有一定的长度。
WTForms 还使用 CSRF 代币来提供保护,以防止 CSRF 攻击,这些攻击允许攻击者在用户身份验证的 Web 应用程序上执行不必要的操作。成功的 CSRF 攻击可以迫使用户执行状态改变的请求,例如将资金转移到攻击者的银行账户中,在银行应用程序中更改用户的电子邮件地址等。
在本教程中,您将构建一个小型的Web应用程序,该应用程序将有一个页面,用于显示存储在Python列表中的课程,而索引页面将有一个形式,用于输入课程标题,其描述,价格,可用性和水平(初学者,中级或高级)。
前提条件
*本地 Python 3 编程环境. 在 [如何安装和设置Python 3的本地编程环境]系列(https://www.digitalocean.com/community/tutorial_series/how-to-install-and-set-up-a-local-programming-environment-for-python-3)中跟随操作系统的教程. 在本教程中,您将调用项目目录 flask_app
- 了解基本的 Flask 概念,如路线、视图功能和模板。如果您不熟悉 Flask,请参阅 如何使用 Flask 和 Python 创建您的第一个 Web 应用程序和 如何在 Flask 应用程序中使用模板。
- 了解基本的 HTML 概念。您可以查看我们的 如何使用 HTML 网站教程系列以获得背景知识.(_
步骤 1 — 安装 Flask 和 Flask-WTF
在此步骤中,您将安装 Flask 和 Flask-WTF,这也将自动安装 WTForms 库。
随着虚拟环境的启用,使用管道
来安装Flask和Flask-WTF:
1pip install Flask Flask-WTF
一旦安装成功完成,您将在输出结束时看到一个类似于以下的行:
1[secondary_label Output]
2Successfully installed Flask-2.0.2 Flask-WTF-1.0.0 Jinja2-3.0.3 MarkupSafe-2.0.1 WTForms-3.0.0 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1
正如你所看到的,WTForms库也被安装为Flask-WTF包的依赖性。
现在你已经安装了所需的Python包,你将下一步设置一个Web表单。
步骤2 - 设置表格
在此步骤中,您将使用从 WTForms 库导入的字段和验证器设置 Web 表单。
您将设置以下领域:
- **标题:**课程标题的文本输入字段
- **描述:**课程描述的文本区域字段
- **价格:**课程价格的整数字段
- **水平:**课程级别的无线电字段有三种选择:初学者,中学者和高级
- **可用:**一个检查框字段,表示课程是否目前可用
首先,在您的flask_app
目录中打开一个名为forms.py
的新文件,该文件将包含您在应用程序中需要的表单:
1nano forms.py
此文件将有一个代表您的 Web 表格的类别. 添加以下导入在顶部:
1[label flask_app/forms.py]
2from flask_wtf import FlaskForm
3from wtforms import (StringField, TextAreaField, IntegerField, BooleanField,
4 RadioField)
5from wtforms.validators import InputRequired, Length
要构建网页表格,您将创建一个FlaskForm
基础类的子类,您将其从flask_wtf
包中导入。
您从 WTForms 库中导入以下 字段:
StringField
:文本输入TextAreaField
:文本区域字段IntegerField
:整数字段BooleanField
:检查框字段RadioField
:用于显示用户可选择的无线电按钮列表的字段
在从 wtforms.validators 导入InputRequired,长度
行中,您将导入验证器用于字段,以确保用户提交有效数据。
接下来,在进口
语句后添加下面的 类:
1[label flask_app/forms.py]
2
3class CourseForm(FlaskForm):
4 title = StringField('Title', validators=[InputRequired(),
5 Length(min=10, max=100)])
6 description = TextAreaField('Course Description',
7 validators=[InputRequired(),
8 Length(max=200)])
9 price = IntegerField('Price', validators=[InputRequired()])
10 level = RadioField('Level',
11 choices=['Beginner', 'Intermediate', 'Advanced'],
12 validators=[InputRequired()])
13 available = BooleanField('Available', default='checked')
保存并关闭文件。
在此CourseForm
类中,您将继承从您之前导入的FlaskForm
基础类。 您将表单字段的集合定义为类变量,使用您从 WTForms 库导入的表单字段。
您可以通过从wtforms.validators
模块中导入的验证器列表来定义每个字段的验证器。
InputRequired
: 表示该字段不应该是空的长度
: 需要两个参数;min
设置为10' 以确保标题长度至少为 10 个字符,而
max设置为
100' 以确保标题长度不超过 100 个字符。
描述文本区域域有一个InputRequired
验证器和一个Length
验证器,其max
参数设置为200
,没有min
参数的值,这意味着唯一的要求是它不超过200个字符。
类似地,您定义了名为价格
的课程价格所需的整数字段。
水平
字段是一个具有多个选择的无线电字段,您在Python列表中定义选项并将其传输到选择
参数中,您还使用InputRequired
验证器根据需要定义该字段。
该可用
字段是一个检查框的字段. 您通过将其转移到默认
参数来设置默认的已检查
值。
有关如何使用 WTForms 库的更多信息,请参阅 WTForms 文档上的 Crash Course 页面。
您已经在forms.py文件中配置了网页表格,接下来,您将创建一个Flask应用程序,导入该表格,并在索引页面上显示其字段。
步骤 3 – 显示 Web 表格和课程
在此步骤中,您将创建一个Flask应用程序,在索引页面上显示您在上一步创建的Web表单,并创建课程列表和页面以显示课程。
当您的编程环境启用并安装Flask时,请打开名为app.py
的文件,在您的flask_app
目录中进行编辑:
1nano app.py
此文件将从 Flask 导入所需的类和助手,并从 forms.py 文件中导入 CourseForm
. 您将构建课程列表,然后实例表格并将其传输到模板文件中。
1[label flask_app/app.py]
2from flask import Flask, render_template, redirect, url_for
3from forms import CourseForm
4
5app = Flask(__name__)
6app.config['SECRET_KEY'] = 'your secret key'
7
8courses_list = [{
9 'title': 'Python 101',
10 'description': 'Learn Python basics',
11 'price': 34,
12 'available': True,
13 'level': 'Beginner'
14 }]
15
16@app.route('/', methods=('GET', 'POST'))
17def index():
18 form = CourseForm()
19 return render_template('index.html', form=form)
保存并关闭文件。
以下是从 Flask 导入的内容:
- 创建 Flask 应用程序实例的
Flask
类 - 返回索引模板的
render_template()
函数 - 重定向() 函数 在添加新课程后将用户重定向到课程页面
- 构建 URL 的
url_for()
函数
首先从forms.py文件中导入CourseForm()
类,然后创建一个名为app
的Flask应用程序实例。
您已为 WTForms 设置一个 secret key 配置,用于生成 CSRF 代币来保护您的 Web 表单. 秘密密密钥应该是一个长的随机字符串. 请参阅 如何在 Flask 应用程序中使用 Web 表单的步骤 3 有关如何获取秘密密密钥的更多信息。
然后你创建一个名为courses_list
的字典列表,该词典目前有一个名为Python 101
的示例课程。在这里,你将使用Python列表作为演示目的的数据存储库。在现实世界的情况下,你将使用SQLite等数据库。 参阅如何在Flask应用程序中使用SQLite数据库(https://andsky.com/tech/tutorials/how-to-use-an-sqlite-database-in-a-flask-application),了解如何使用数据库来存储你的课程数据。
您使用app.route()
装饰器在index()
视图函数中创建一个/
主路线,它在methods
参数中接受GET
和POST
HTTP 方法。
您实例化代表 Web 表单的 CourseForm()
类,并将该实例保存到名为 form
的变量中,然后返回对 render_template()
函数的呼叫,并将其传递给名为 index.html
的模板文件和表单实例。
要在索引页面上显示网页表格,您首先将创建一个基础模板,该模板将包含其他模板也将使用的所有基本HTML代码,以避免代码重复。
在您的flask_app
目录中创建一个模板
文件夹,Flask 搜索模板,然后打开名为base.html
的模板文件,它将是其他模板的基板模板:
1mkdir templates
2nano templates/base.html
将下列代码添加到 base.html
文件中,以创建一个 navbar 和一个内容块的 base 模板:
1[label flask_app/templates/base.html]
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="UTF-8">
6 <title>{% block title %} {% endblock %} - FlaskApp</title>
7 <style>
8 nav a {
9 color: #d64161;
10 font-size: 3em;
11 margin-left: 50px;
12 text-decoration: none;
13 }
14 </style>
15</head>
16<body>
17 <nav>
18 <a href="{{ url_for('index') }}">FlaskApp</a>
19 <a href="#">About</a>
20 </nav>
21 <hr>
22 <div class="content">
23 {% block content %} {% endblock %}
24 </div>
25</body>
26</html>
此基础模板包含您在其他模板中需要重复使用的所有HTML锅炉板。标题
块将被更换为为每个页面设置一个标题,而内容
块将被替换为每个页面的内容。导航栏有两个链接,一个用于索引页面,其中您使用url_for()
辅助函数链接到index()
视图函数,另一个用于关于页面,如果您选择在应用程序中包含一个链接。
保存并关闭文件。
接下来,打开一个名为index.html
的模板,这是你在app.py
文件中提到的模板:
1nano templates/index.html
此文件将包含您通过form
变量传递到index.html
模板的网页表格,添加以下代码:
1[label flask_app/templates/index.html]
2{% extends 'base.html' %}
3
4{% block content %}
5 <h1>{% block title %} Add a New Course {% endblock %}</h1>
6
7 <form method="POST" action="/">
8 {{ form.csrf_token }}
9 <p>
10 {{ form.title.label }}
11 {{ form.title(size=20) }}
12 </p>
13
14 {% if form.title.errors %}
15 <ul class="errors">
16 {% for error in form.title.errors %}
17 <li>{{ error }}</li>
18 {% endfor %}
19 </ul>
20 {% endif %}
21
22 <p>
23 {{ form.description.label }}
24 </p>
25 {{ form.description(rows=10, cols=50) }}
26
27 {% if form.description.errors %}
28 <ul class="errors">
29 {% for error in form.description.errors %}
30 <li>{{ error }}</li>
31 {% endfor %}
32 </ul>
33 {% endif %}
34
35 <p>
36 {{ form.price.label }}
37 {{ form.price() }}
38 </p>
39
40 {% if form.price.errors %}
41 <ul class="errors">
42 {% for error in form.price.errors %}
43 <li>{{ error }}</li>
44 {% endfor %}
45 </ul>
46 {% endif %}
47
48 <p>
49 {{ form.available() }} {{ form.available.label }}
50 </p>
51
52 {% if form.available.errors %}
53 <ul class="errors">
54 {% for error in form.available.errors %}
55 <li>{{ error }}</li>
56 {% endfor %}
57 </ul>
58 {% endif %}
59
60 <p>
61 {{ form.level.label }}
62 {{ form.level() }}
63 </p>
64
65 {% if form.level.errors %}
66 <ul class="errors">
67 {% for error in form.level.errors %}
68 <li>{{ error }}</li>
69 {% endfor %}
70 </ul>
71 {% endif %}
72
73 <p>
74 <input type="submit" value="Add">
75 </p>
76 </form>
77
78{% endblock %}
保存并关闭文件。
您将基础模板扩展,并在一个<h1>
标签中设置一个标题,然后您将网页表单字段转换为<form>
标签,将其方法设置为POST
,并将操作转移到/
主路线,即索引页面。
您可以使用form.field.label
语法渲染每个字段,并使用form.field.label
语法渲染其标签。您可以将参数传输到该字段以控制其显示方式。例如,您将标题输入字段的大小设置为{{form.title(size=20) }}
,并通过参数行
和cols
来设置描述文本区域的行和列的数量,就像您通常在HTML中所做的那样。
您可以使用语法if form.field.errors
检查验证错误,如果一个字段有错误,则使用for
循环循环循环通过它们,并在字段下面列出它们。
在您的flask_app
目录中启用虚拟环境时,请使用FLASK_APP
环境变量告诉Flask关于该应用程序(app.py
在这种情况下)。然后将FLASK_ENV
环境变量设置为development
,以便在开发模式下运行应用程序,并获取调试器的访问。有关Flask调试器的更多信息,请参阅如何处理Flask应用程序中的错误
(LINK0
))。
1export FLASK_APP=app
2export FLASK_ENV=development
接下来,运行应用程序:
1flask run
当开发服务器运行时,请使用您的浏览器访问以下URL:
1http://127.0.0.1:5000/
您将看到在索引页面上显示的 Web 表格:
尝试提交表单而不填写标题. 你会看到一个错误消息,通知你标题是必需的. 通过提交错误的数据(如短标题小于10个字符长度,或描述超过200个字符长度)来查看其他错误消息来尝试表单。
用有效的数据填写表单到目前为止没有任何效果,因为您没有处理表单提交的代码。
现在,您需要一个页面来显示您在列表中的课程. 后来,处理网页表格数据将添加一个新课程到列表,并将用户重定向到课程页面,以查看新课程添加到它。
让开发服务器运行,然后打开另一个终端窗口。
接下来,打开app.py
来添加课程路线:
1nano app.py
添加下列路径到文件的末尾:
1[label flask_app/app.py]
2# ...
3
4@app.route('/courses/')
5def courses():
6 return render_template('courses.html', courses_list=courses_list)
保存并关闭文件。
此路径将显示一个名为courses.html
的模板,并将其传输到courses_list
列表中。
然后创建courses.html
模板以显示课程:
1nano templates/courses.html
添加以下代码:
1[label flask_app/templates/courses.html]
2{% extends 'base.html' %}
3
4{% block content %}
5 <h1>{% block title %} Courses {% endblock %}</h1>
6 <hr>
7 {% for course in courses_list %}
8 <h2> {{ course['title'] }} </h2>
9 <h4> {{ course['description'] }} </h4>
10 <p> {{ course['price'] }}$ </p>
11 <p><i>({{ course['level'] }})</i></p>
12 <p>Availability:
13 {% if course['available'] %}
14 Available
15 {% else %}
16 Not Available
17 {% endif %}</p>
18 <hr>
19 {% endfor %}
20{% endblock %}
保存并关闭文件。
您通过courses_list
列表中的项目设置一个标题和循环。您将标题显示在<h2>
标签中,描述显示在<h4>
标签中,价格和课程水平显示在<p>
标签中。
使用您的浏览器前往课程页面:
1http://127.0.0.1:5000/courses/
你会看到一页显示一个课程,因为到目前为止,你的课程列表中只有一门课程:
接下来,打开base.html
,在导航栏中添加链接到课程页面:
1nano templates/base.html
编辑它看起来如下:
1[label flask_app/templates/base.html]
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="UTF-8">
6 <title>{% block title %} {% endblock %} - FlaskApp</title>
7 <style>
8 nav a {
9 color: #d64161;
10 font-size: 3em;
11 margin-left: 50px;
12 text-decoration: none;
13 }
14 </style>
15</head>
16<body>
17 <nav>
18 <a href="{{ url_for('index') }}">FlaskApp</a>
19 <a href="{{ url_for('courses') }}">Courses</a>
20 <a href="#">About</a>
21 </nav>
22 <hr>
23 <div class="content">
24 {% block content %} {% endblock %}
25 </div>
26</body>
27</html>
保存并关闭文件。
更新索引页面,您将在导航栏中看到一个新的 课程链接。
您已经创建了应用程序所需的页面:一个索引页面,包含添加新课程的网页表,以及显示您列出的课程的页面。
要使应用程序功能,您需要通过验证它并将其添加到课程列表来处理用户提交的Web表单数据。
步骤 4 – 访问表单数据
在此步骤中,您将访问用户提交的数据,验证并将其添加到课程列表中。
打开app.py
以添加用于在index()
函数内处理 Web 表单数据的代码:
1nano app.py
编辑index()
函数以显示如下:
1[label flask_app/app.py]
2# ...
3@app.route('/', methods=('GET', 'POST'))
4def index():
5 form = CourseForm()
6 if form.validate_on_submit():
7 courses_list.append({'title': form.title.data,
8 'description': form.description.data,
9 'price': form.price.data,
10 'available': form.available.data,
11 'level': form.level.data
12 })
13 return redirect(url_for('courses'))
14 return render_template('index.html', form=form)
保存和关闭文件
在这里,您在表单
对象上呼叫validate_on_submit()
方法,该方法会检查请求是否是一个 POST 请求,并运行您为每个字段配置的验证器。
如果提交的表单数据是有效的,则条件为真
,并且将执行如果
声明下的代码。您构建一个课程字典,并使用附加
方法将新课程添加到courses_list
列表中。
随着开发服务器运行,请访问索引页面:
1http://127.0.0.1:5000/
用有效的数据填写表格并提交它,您将被重定向到课程
页面,您将看到新课程显示在其上。
结论
您创建了一个 Flask 应用程序,该应用程序具有使用 Flask-WTF 扩展和 WTForms 库构建的 Web 表单,该表单有几种类型的字段来接收用户的数据,使用特殊的 WTForms 验证器验证它,并将其添加到数据存储中。
如果您想了解更多关于 Flask 的信息,请参阅 如何使用 Flask 创建网站系列的其他教程。