如何在Flask应用程序中使用Web表单

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。

介绍

Web 表单(例如文本字段和文本区域)使用户能够将数据发送到您的应用程序以使用它来执行操作,或者将更大的文本区域发送到应用程序。 例如,在社交媒体应用程序中,您可能会为用户提供一个框,他们可以在其中向页面添加新内容。 另一个示例是登录页面,您可以在其中为用户提供一个文本字段以输入其用户名,并为用户提供一个密码字段以输入其密码。 服务器(在这种情况下是您的 Flask 应用程序)使用用户提交的数据,如果数据有效,则将其登录,或者使用 Invalid credentials! 之类的消息进行响应,以通知用户他们提交的数据不是正确的。

Flask 是一个轻量级的 Python Web 框架,它为使用 Python 语言创建 Web 应用程序提供了有用的工具和功能。 在本教程中,您将构建一个演示如何使用 Web 表单的小型 Web 应用程序。 该应用程序将有一个用于显示存储在 Python 列表中的消息的页面,以及一个用于添加新消息的页面。 当用户提交无效数据时,您还将使用 消息闪烁 通知用户错误。

先决条件

第 1 步 — 显示消息

在这一步中,您将创建一个带有索引页面的 Flask 应用程序,用于显示存储在 Python 字典列表中的消息。

首先打开一个名为 app.py 的新文件进行编辑:

nano app.py

app.py 文件中添加以下代码以创建具有单个路由的 Flask 服务器:

烧瓶应用程序/app.py

from flask import Flask, render_template

app = Flask(__name__)

messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]

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

保存并关闭文件。

在此文件中,首先从 flask 包中导入 Flask 类和 render_template() 函数。 然后使用 Flask 类创建一个名为 app 的新 应用程序实例 ,传递 Flask 设置所需的特殊 __name__ 变量幕后的一些路径。 教程 如何在 Flask 应用程序中使用模板 介绍了渲染模板。

然后创建一个名为 messages 的全局 Python 列表,其中包含 Python 字典。 每个字典有两个键:title 为消息标题,content 为消息内容。 这是数据存储方法的简化示例; 在实际场景中,您将使用永久保存数据并允许您更有效地操作它的数据库。

创建 Python 列表后,使用 @app.route() 装饰器创建一个名为 index()视图函数 。 在其中,您返回对 render_template() 函数的调用,该函数向 Flask 指示路由应该显示 HTML 模板。 您将此模板命名为 index.html(稍后将创建它),并将一个名为 messages 的变量传递给它。 此变量保存您之前声明为值的 messages 列表,并使其可用于 HTML 模板。 视图函数在教程 How To Create Your First Web Application Using Flask and Python 3 中有介绍。

接下来,在 Flask 搜索模板的 flask_app 目录中创建一个 templates 文件夹,然后打开一个名为 base.html 的模板文件,其中包含其他模板将继承以避免的代码代码重复:

mkdir templates
nano templates/base.html

base.html 文件中添加以下代码以创建带有导航栏和内容块的基本模板:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

保存并关闭文件。

此基本模板包含您需要在其他模板中重用的所有 HTML 样板。 title 块将被替换为每个页面设置标题,content 块将被替换为每个页面的内容。 导航栏有两个链接,一个用于索引页面,您使用 url_for() 辅助函数链接到 index() 视图函数,另一个用于“关于”页面(如果您选择包含一个)在您的应用程序中。

接下来,打开一个名为 index.html 的模板。 这是您在 app.py 文件中引用的模板:

nano templates/index.html

向其中添加以下代码:

flask_app/templates/index.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Messages {% endblock %}</h1>
    {% for message in messages %}
        <div class='message'>
            <h3>{{ message['title'] }}</h3>
            <p>{{ message['content'] }}</p>
        </div>
    {% endfor %}
{% endblock %}

保存并关闭文件。

在此代码中,您扩展了 base.html 模板并替换了 content 块的内容。 您使用的 <h1> 标题也用作标题。

{% for message in messages %} 行中使用 Jinja for loop 遍历 messages 列表中的每条消息。 您使用 <div> 标记来包含消息的标题和内容。 您在 <h3> 标题中显示标题,在 <p> 标记中显示内容。

在激活虚拟环境的 flask_app 目录中,使用 FLASK_APP 环境变量告诉 Flask 应用程序(在本例中为 app.py):

export FLASK_APP=app

然后将 FLASK_ENV 环境变量设置为 development 以在开发模式下运行应用程序并访问调试器。 有关 Flask 调试器的更多信息,请参阅 如何处理 Flask 应用程序中的错误 。 使用以下命令执行此操作(在 Windows 上,使用 set 而不是 export):

export FLASK_ENV=development

接下来,运行应用程序:

flask run

在开发服务器运行的情况下,使用浏览器访问以下 URL:

http://127.0.0.1:5000/

您将在索引页面上显示的 messages 列表中看到消息:

现在您已经设置了 Web 应用程序并显示了消息,您需要一种方法来允许用户将新消息添加到索引页面。 这是通过网络表单完成的,您将在下一步中进行设置。

第 2 步 — 设置表格

在此步骤中,您将在应用程序中创建一个页面,允许用户通过 Web 表单将新消息添加到消息列表中。

让开发服务器保持运行并打开一个新的终端窗口。

首先,打开您的 app.py 文件:

nano app.py

将以下路由添加到文件末尾:

烧瓶应用程序/app.py

# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

保存并关闭文件。

/create 路由具有 methods 参数和元组 ('GET', 'POST') 以接受 GETPOST 请求。 GETPOSTHTTP 方法。 默认情况下,只接受 GET 请求,这些请求用于检索数据,例如向服务器请求索引页面或关于页面。 POST 请求用于将数据提交到特定的路由,这往往会改变服务器上的数据。

在此示例中,您将使用 GET 请求请求 create 页面。 创建页面将有一个带有输入字段和提交按钮的 Web 表单。 当用户填写 Web 表单并单击提交按钮时,会向 /create 路由发送 POST 请求。 在那里您处理请求,验证提交的数据以确保用户没有提交空表单,并将其添加到 messages 列表。

create() 视图函数目前只做一件事:当它收到一个常规的 GET 请求时,渲染一个名为 create.html 的模板。 您现在将创建此模板,然后在下一步中编辑函数以处理 POST 请求。

打开一个名为 create.html 的新模板文件:

nano templates/create.html

向其中添加以下代码:

flask_app/templates/create.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Message {% endblock %}</h1>
    <form method="post">
        <label for="title">Title</label>
        <br>
        <input type="text" name="title"
               placeholder="Message title"
               value="{{ request.form['title'] }}"></input>
        <br>

        <label for="content">Message Content</label>
        <br>
        <textarea name="content"
                  placeholder="Message content"
                  rows="15"
                  cols="60"
                  >{{ request.form['content'] }}</textarea>
        <br>
        <button type="submit">Submit</button>
    </form>
{% endblock %}

保存并关闭文件。

在此代码中,您扩展了 base.html 模板并将 content 块替换为用作页面标题的 <h1> 标题。 在 <form> 标记中,您将 method 属性设置为 post,以便表单数据作为 POST 请求发送到服务器。

在表单中,您有一个名为 title 的文本输入字段; 这是您将在应用程序上用于访问标题表单数据的名称。 你给 <input> 标签一个 {{ request.form['title'] }}value。 这对于恢复用户输入的数据很有用,因此在出现问题时不会丢失。 例如,如果用户忘记填写所需的 content 文本区域,则会向服务器发送请求并返回错误消息作为响应,但标题中的数据不会丢失,因为它将保存在 request 全局对象中,并且可以通过 request.form['title'] 访问。

在标题输入字段之后,您添加一个名为 content 的文本区域,其值为 {{ request.form['content'] }},原因与前面提到的相同。

最后,表单末尾有一个提交按钮。

现在,随着开发服务器的运行,使用浏览器导航到 /create 路由:

http://127.0.0.1:5000/create

您将看到一个“添加新消息”页面,其中包含消息标题的输入字段、消息内容的文本区域和提交按钮。

此表单向您的 create() 视图函数提交 POST 请求。 但是,函数中还没有处理 POST 请求的代码,因此在填写表单并提交后没有任何反应。 在下一步中,您将在提交表单时处理传入的 POST 请求。 您将检查提交的数据是否有效(不为空),并将消息标题和内容添加到 messages 列表中。

第 3 步 - 处理表单请求

在此步骤中,您将在应用程序端处理表单请求。 您将通过您在上一步中创建的表单访问用户提交的表单数据,并将其添加到消息列表中。 当用户提交无效数据时,您还将使用 消息闪烁 通知用户。 闪现消息 只会显示一次,并且会在下一个请求时消失(例如,如果您导航到另一个页面)。

打开app.py文件进行编辑:

nano app.py

首先,您将从 Flask 框架中导入以下内容:

  • 全局 request 对象用于访问将通过您在上一步中构建的 HTML 表单提交的传入请求数据。
  • url_for() 函数用于生成 URL。
  • flash() 函数在处理请求时闪烁消息(通知用户一切顺利,或者如果提交的数据无效,则通知他们问题)。
  • redirect() 函数将客户端重定向到不同的位置。

将这些导入添加到文件的第一行:

烧瓶应用程序/app.py

from flask import Flask, render_template, request, url_for, flash, redirect

# ...

flash() 函数将闪过的消息存储在客户端的浏览器会话中,这需要设置一个密钥。 此密钥用于保护会话,这允许 Flask 记住从一个请求到另一个请求的信息,例如从新消息页面移动到索引页面。 用户可以访问存储在会话中的信息,但不能修改它,除非他们拥有密钥,因此您绝不能允许任何人访问您的密钥。 有关详细信息,请参阅 Flask 会话文档

密钥应该是一个很长的随机字符串。 您可以使用带有 os.urandom() 方法的 os 模块生成密钥,该方法返回适合加密使用的随机字节字符串。 要使用它获取随机字符串,请打开一个新终端并使用以下命令打开 Python 交互式 shell:

python

在Python交互shell中,从标准库中导入os模块,调用os.urandom()方法如下:

import os
os.urandom(24).hex()

您将获得类似于以下内容的字符串:

Output
'df0331cefc6c2b9a5d0208a726a5d1c0fd37324feba25506'

您可以使用获得的字符串作为您的密钥。

要设置密钥,请通过 app.config 对象将 SECRET_KEY 配置添加到您的应用程序。 在定义 messages 变量之前,将其直接添加到 app 定义之后:

烧瓶应用程序/app.py

# ...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]
# ...

接下来,将 create() 视图函数修改为如下所示:

烧瓶应用程序/app.py

# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        elif not content:
            flash('Content is required!')
        else:
            messages.append({'title': title, 'content': content})
            return redirect(url_for('index'))

    return render_template('create.html')

if 语句中,您通过比较 request.method == 'POST' 确保仅当请求是 POST 请求时才执行其后面的代码。

然后,您从 request.form 对象中提取提交的标题和内容,使您可以访问请求中的表单数据。 如果未提供标题,则将满足条件 if not title。 在这种情况下,您使用 flash() 函数向用户显示一条消息,通知他们需要标题。 这会将消息添加到 闪烁消息 列表中。 您稍后将在页面上显示这些消息,作为 base.html 模板的一部分。 类似地,如果没有提供内容,则条件elif not content将被满足。 如果是这样,则将 'Content is required!' 消息添加到闪烁的消息列表中。

如果正确提交了消息的标题和内容,则使用 messages.append({'title': title, 'content': content}) 行将新字典添加到 messages 列表中,其中包含用户提供的标题和内容。 然后使用 redirect() 函数将用户重定向到索引页面。 您使用 url_for() 函数链接到索引页面。

保存并关闭文件。

现在,使用您的网络浏览器导航到 /create 路线:

http://127.0.0.1:5000/create

用您选择的标题和一些内容填写表格。 提交表单后,您将看到索引页面上列出的新消息。

最后,您将显示闪烁的消息并将“新消息”页面的链接添加到 base.html 模板中的导航栏,以便轻松访问这个新页面。 打开基本模板文件:

nano templates/base.html

通过在 <nav> 标签内导航栏中的 FlaskApp 链接后添加新的 <a> 标签来编辑文件。 然后在 content 块正上方添加一个新的 for 循环,以在导航栏下方显示闪烁的消息。 这些消息在 Flask 提供的特殊 get_flashed_messages() 函数中可用。 然后为每条消息添加一个名为 alert 的类属性,并在 <style> 标记内为其提供一些 CSS 属性:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .alert {
            padding: 20px;
            margin: 5px;
            color: #970020;
            background-color: #ffd5de;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% for message in get_flashed_messages() %}
            <div class="alert">{{ message }}</div>
        {% endfor %}
        {% block content %} {% endblock %}
    </div>
</body>
</html>

保存并关闭文件,然后在浏览器中重新加载 https://127.0.0.1:5000。 导航栏现在将有一个链接到 /create 路线的“创建”项目。

要查看 Flash 消息的工作原理,请转到“创建”页面,然后单击“提交”按钮而不填写这两个字段。 您将收到如下所示的消息:

返回索引页面,您会看到导航栏下方闪烁的消息消失了,即使它们显示为基本模板的一部分。 如果它们不是闪烁的消息,它们也会显示在索引页面上,因为它也继承自基本模板。

尝试提交带有标题但没有内容的表单。 您将看到消息“需要内容!”。 单击导航栏中的 FlaskApp 链接返回索引页面,然后单击返回按钮返回创建页面。 您会看到消息内容仍然存在。 这仅在您单击“后退”按钮时才有效,因为它会保存先前的请求。 单击导航栏中的创建链接将发送一个新请求,该请求将清除表单,因此闪烁的消息将消失。

您现在知道如何接收用户输入、如何验证它以及如何将其添加到数据源。

注意: 添加到 messages 列表的消息会在服务器停止时消失,因为 Python 列表只保存在内存中,要永久保存您的消息,您需要使用SQLite 之类的数据库。 查看 如何在 Python 3 中使用 sqlite3 模块,了解如何在 Python 中使用 SQLite。


结论

您创建了一个 Flask 应用程序,用户可以在其中将消息添加到索引页面上显示的消息列表中。 您创建了一个 Web 表单,处理了用户通过表单提交的数据,并将其添加到您的消息列表中。 您还使用 Flash 消息在用户提交无效数据时通知他们。

如果您想了解更多关于 Flask 的信息,请查看 Flask 系列中的其他教程