如何在Flask应用程序中使用MongoDB

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

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

介绍

在 Web 应用程序中,您通常需要一个数据库,它是一个有组织的数据集合。 您使用数据库来存储和维护可以有效检索和操作的持久数据。 例如,在社交媒体应用程序中,您有一个数据库,其中用户数据(个人信息、帖子、评论、关注者)以一种可以有效操作的方式存储。 您可以根据不同的要求和条件,将数据添加到数据库、检索、修改或删除数据库。 在 Web 应用程序中,这些要求可能是用户添加新帖子、删除帖子或删除他们的帐户,这可能会或可能不会删除他们的帖子。 您为操作数据而执行的操作将取决于应用程序中的特定功能。 例如,您可能不希望用户添加没有标题的帖子。

Flask 是一个轻量级的 Python Web 框架,它提供了有用的工具和功能,用于用 Python 语言创建 Web 应用程序。 MongoDB 是一个通用的、面向文档的 NoSQL 数据库程序,它使用类似 JSON 的文档来存储数据。 与关系数据库中使用的表格关系不同,类似 JSON 的文档允许灵活和动态的模式,同时保持简单性。 一般来说,NoSQL 数据库具有水平扩展的能力,使其适用于大数据和实时应用程序。

在本教程中,您将构建一个小型待办事项列表 Web 应用程序,演示如何使用 PyMongo 库,这是一个 MongoDB 数据库驱动程序,允许您在 Python 中与 MongoDB 数据库进行交互。 您将使用它与 Flask 一起执行基本任务,例如连接到数据库服务器、创建在 MongoDB 中存储一组文档的集合、将数据插入集合以及从集合中检索和删除数据。

先决条件

第 1 步 — 设置 PyMongo 和 Flask

在这一步中,您将安装 Flask 和 PyMongo 库。

激活虚拟环境后,使用 pip 安装 Flask 和 PyMongo:

pip install Flask pymongo

安装成功完成后,您将在输出末尾看到类似于以下内容的行:

Output
Successfully installed Flask-2.0.2 Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1 pymongo-4.0.1

现在您已经安装了所需的 Python 包,您将连接到 MongoDB 服务器并创建一个集合。

第 2 步 - 连接到 MongoDB 服务器并创建集合

在这一步中,您将使用 PyMongo 库创建一个客户端,您将使用它与您的 MongoDB 服务器交互、创建一个数据库,然后创建一个集合来存储您的待办事项。

激活您的编程环境后,在 flask_app 目录中打开一个名为 app.py 的文件进行编辑:

nano app.py

该文件将从 Flask 和 PyMongo 库中导入必要的类和助手。 您将与 MongoDB 服务器交互以创建数据库并为待办事项创建集合。 将以下代码添加到 app.py

烧瓶应用程序/app.py

from flask import Flask
from pymongo import MongoClient

app = Flask(__name__)

client = MongoClient('localhost', 27017)

db = client.flask_db
todos = db.todos

保存并关闭文件。

在这里您导入 Flask 类,您可以使用它来创建一个名为 app 的 Flask 应用程序实例。

您导入 MongoClient 用于为名为 client 的 MongoDB 实例创建客户端对象,它允许您连接 MongoDB 服务器并与之交互。 当您实例化 MongoClient() 时,您将 MongoDB 服务器的主机(在我们的示例中为 localhost)和端口(此处为 27017)传递给它。

笔记:

强烈 建议您按照我们关于 如何在 Ubuntu 20.04 上保护 MongoDB 的指南来加强 MongoDB 安装的安全性。 一旦它得到保护,您就可以 配置 MongoDB 以接受远程连接

在 MongoDB 中启用身份验证后,您需要在创建 MongoClient() 的实例时传递额外的 usernamepassword 参数,如下所示:

client = MongoClient('localhost', 27017, username='username', password='password')

然后使用 client 实例创建一个名为 flask_db 的 MongoDB 数据库,并将对它的引用保存在名为 db 的变量中。

然后使用 db 变量在 flask_db 数据库上创建一个名为 todos 的集合。 集合在 MongoDB 中存储一组文档,就像关系数据库中的表一样。

在 MongoDB 中,数据库和集合是惰性创建的。 这意味着即使您执行 app.py 文件,在创建第一个文档之前,不会真正执行与数据库相关的代码。 您将创建一个带有页面的小型 Flask 应用程序,该页面允许用户在下一步中将待办事项文档插入到您的 todos 集合中。 添加第一个待办事项文档后,flask_db 数据库和 todos 集合将在您的 MongoDB 服务器上创建。

要获取当前数据库的列表,请打开一个新终端,然后使用以下命令启动 mongo shell:

mongo

将打开一个提示,您可以使用以下命令检查您的数据库:

show dbs

如果这是新安装的 MongoDB,输出将列出 adminconfiglocal 数据库。

您会注意到 flask_db 还不存在。 让 mongo shell 在终端窗口中运行并继续下一步。

第 3 步 — 创建用于添加和显示待办事项的网页

在此步骤中,您将创建一个带有 Web 表单的网页,该表单允许用户添加待办事项并将它们显示在同一页面上。

激活您的编程环境后,打开 app.py 文件进行编辑:

nano app.py

首先,从 flask 添加以下导入:

烧瓶应用程序/app.py

from flask import Flask, render_template, request, url_for, redirect
from pymongo import MongoClient

# ...

在这里,您导入将用于呈现 HTML 模板的 render_template() 辅助函数、用于访问用户将提交的数据的 request 对象、用于生成 URL 的 url_for() 函数, 和 redirect() 函数在添加待办事项后将用户重定向回索引页面。

然后在文件末尾添加以下路由:

烧瓶应用程序/app.py

# ...


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

保存并关闭文件。

在此路由中,您将元组 ('GET', 'POST') 传递给 methods 参数以允许 GET 和 POST 请求。 GET 请求用于从服务器检索数据。 POST 请求用于将数据发布到特定路由。 默认情况下,只允许 GET 请求。 当用户第一次使用 GET 请求请求 / 路由时,将呈现一个名为 index.html 的模板文件。 您稍后将编辑此路由以处理用户填写和提交 Web 表单以创建新待办事项时的 POST 请求。

接下来在您的 flask_app 目录中创建一个模板文件夹,以及您在前面的路线中引用的 index.html 模板:

mkdir templates
nano templates/index.html

index.html 文件中添加以下代码:

flask_app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
    <style>
        .todo {
            padding: 20px;
            margin: 10px;
            background-color: #eee;
        }
    </style>
</head>
<body>
    <h1>FlaskTODO</h1>
    <hr>
    <div class="content">
    <form method="post">
        <p>
            <b><label for="content">Todo content</label></b>
        </p>
        <p>
            <input type="text" name="content"
                placeholder="Todo Content"></input>
        </p>

        <p>
            <b><label for="degree">Degree</label></b>
        </p>
        <p>
            <input id="degree-0" name="degree" required type="radio" value="Important">
            <label for="degree-0">Important</label>
        </p>
        <p>
            <input id="degree-1" name="degree" required type="radio" value="Unimportant">
            <label for="degree-1">Unimportant</label>
        </p>
        <button type="submit">Submit</button>
    </form>
    </div>
</body>
</html>

保存并关闭文件。

在这里,您有一个带有标题、一些样式、标题和 Web 表单的基本 HTML 页面。 在 Web 表单中,您将 method 属性设置为 post 以指示表单将提交 POST 请求。 您有一个名称为 content 的待办事项内容的文本输入字段,您将使用它来访问 / 路由中的标题数据。 您还有两个名为 degree 的 HTML 单选按钮,允许用户指定每个待办事项的重要程度:他们可以选择 Important 选项或 创建待办事项时不重要的 选项。 最后,表单末尾有一个 Submit 按钮。

在激活虚拟环境的 flask_app 目录中,使用 FLASK_APP 环境变量告诉 Flask 应用程序(在本例中为 app.py)。 然后将 FLASK_ENV 环境变量设置为 development 以在开发模式下运行应用程序并访问调试器。 有关 Flask 调试器的更多信息,请参阅 如何处理 Flask 应用程序中的错误 。 使用以下命令执行此操作:

export FLASK_APP=app
export FLASK_ENV=development

接下来,运行应用程序:

flask run

注意: 尝试运行应用程序时,您可能会收到 ModuleNotFoundError: No module named 'pymongo' 错误。 要解决此问题,请停用您的虚拟环境并重新激活它。 然后再次运行 flask run 命令。


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

http://127.0.0.1:5000/

您将看到索引页面,其中包含待办事项内容的输入字段、两个用于重要性程度的单选按钮和一个 Submit 按钮。

有关 Web 表单的更多信息,请参阅 如何在 Flask 应用程序中使用 Web 表单。 有关管理 Web 表单的更高级和更安全的方法,请参阅 How To Use and Validate Web Forms with Flask-WTF

如果您填写并提交表单,向服务器发送 POST 请求,则不会发生任何事情,因为您没有处理 / 路由上的 POST 请求。

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

打开 app.py 处理用户提交的 POST 请求,添加到 todos 集合中,并显示在索引页面上:

nano app.py

编辑 / 路线,如下所示:

烧瓶应用程序/app.py

@app.route('/', methods=('GET', 'POST'))
def index():
    if request.method=='POST':
        content = request.form['content']
        degree = request.form['degree']
        todos.insert_one({'content': content, 'degree': degree})
        return redirect(url_for('index'))

    all_todos = todos.find()
    return render_template('index.html', todos=all_todos)

保存并关闭文件。

在这些更改中,您在 if request.method == 'POST' 条件内处理 POST 请求。 您从 request.form 对象中提取用户提交的待办事项内容和重要程度。

您可以在 todos 集合上使用 insert_one() 方法向其中添加一个 todo 文档。 您在 Python 字典中提供待办事项数据,将 'content' 设置为用户在待办事项内容的文本字段中提交的值,并将 'degree' 键设置为单选按钮的值用户选择。 然后重定向到索引页面,该页面将刷新页面并显示新添加的待办事项。

要显示所有保存的待办事项,请在负责处理 POST 请求的代码之外使用 find() 方法,该方法返回 todos 集合中可用的所有待办事项文档。 您将从数据库中获得的待办事项保存在名为 all_todos 的变量中,然后编辑 render_template() 函数调用以将待办事项文档列表传递给 index.html 模板,这将在模板中名为 todos 的变量中可用。

如果刷新索引页面,您可能会收到来自浏览器的消息,要求您确认重新提交表单。 如果您接受,您之前在处理 POST 请求之前提交的待办事项将被添加到数据库中,因为处理表单的代码现在存在于路由中。

因为索引页面还没有显示待办事项的代码,所以您添加的项目将不可见。 如果您允许浏览器重新提交表单,您可以通过打开 mongo shell 并使用以下命令连接到 flask_db 数据库来查看新添加的数据:

use flask_db

然后使用 find() 函数获取数据库中的所有待办事项:

db.todos.find()

如果重新提交了任何数据,您将在输出中看到它。

接下来,打开 index.html 模板以显示您传递给它的 todos 列表的内容:

nano templates/index.html

通过在表单后添加 <hr> 中断和 Jinja for loop 来编辑文件,使文件如下所示:

flask_app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
    <style>
        .todo {
            padding: 20px;
            margin: 10px;
            background-color: #eee;
        }
    </style>
</head>
<body>
    <h1>FlaskTODO</h1>
    <hr>
    <div class="content">
    <form method="post">
        <p>
            <b><label for="content">Todo content</label></b>
        </p>
        <p>
            <input type="text" name="content"
                placeholder="Todo Content"></input>
        </p>

        <p>
            <b><label for="degree">Degree</label></b>
        </p>
        <p>
            <input id="degree-0" name="degree" required type="radio" value="Important">
            <label for="degree-0">Important</label>
        </p>
        <p>
            <input id="degree-1" name="degree" required type="radio" value="Unimportant">
            <label for="degree-1">Unimportant</label>
        </p>
        <button type="submit">Submit</button>
    </form>
    <hr>
    {% for todo in todos %}
        <div class="todo">
            <p>{{ todo['content'] }} <i>({{ todo['degree']}})</i></p>
        </div>
    {% endfor %}

    </div>
</body>
</html>

保存并关闭文件。

在此文件中,您添加一个 <hr> 标记来分隔 Web 表单和待办事项列表。

您在 {% for todo in todos %} 行中使用 for 循环遍历 todos 列表中的每个待办事项。 您在 <p> 标签内显示待办事项内容和重要程度。

现在刷新您的索引页面,填写网络表单,然后提交。 您将在表单下方看到您添加的待办事项。 接下来,您将添加一个按钮以允许用户删除现有的待办事项。

第 4 步 — 删除待办事项

在这一步中,您将添加一个允许用户使用按钮删除待办事项的路由。

首先,您将添加一个接受 POST 请求的新 /id/delete 路由。 您的新 delete() 视图函数将从 URL 中接收要删除的待办事项的 ID,然后使用该 ID 将其删除。

要删除待办事项,您需要将其 ID 作为字符串获取,并且必须在将其传递给集合的删除方法之前将其转换为 ObjectId。 所以你需要从 bson 模块 中导入 ObjectId() 类,该模块处理 BSON (Binary JSON) 编码和解码。

打开app.py进行编辑:

nano app.py

首先,在文件顶部添加以下导入:

烧瓶应用程序/app.py

from bson.objectid import ObjectId

# ...

这是您将用于将字符串 ID 转换为 ObjectId 对象的 ObjectId() 类。

然后在最后添加以下路由:

烧瓶应用程序/app.py

# ...


@app.post('/<id>/delete/')
def delete(id):
    todos.delete_one({"_id": ObjectId(id)})
    return redirect(url_for('index'))

保存并关闭文件。

在这里,不是使用通常的 app.route 装饰器,而是使用 Flask 版本 2.0.0 中引入的 app.post 装饰器,它为常见的 HTTP 方法添加了快捷方式。 例如,@app.post("/login")@app.route("/login", methods=["POST"]) 的快捷方式。 这意味着这个视图函数只接受 POST 请求,并且在浏览器上导航到 /ID/delete 路由将返回 405 Method Not Allowed 错误,因为 Web 浏览器默认使用 GET 请求。 要删除待办事项,用户单击向该路由发送 POST 请求的按钮。

该函数接收要删除的待办事项文档的 ID。 您将此 ID 传递给 todos 集合上的 delete_one() 方法,然后使用之前导入的 ObjectId() 类将收到的字符串 ID 转换为 ObjectId。

删除待办事项文档后,将用户重定向到索引页面。

接下来,编辑 index.html 模板以添加 Delete Todo 按钮:

nano templates/index.html

通过添加一个新的 <form> 标签来编辑 for 循环:

flask_app/templates/index.html

    {% for todo in todos %}
        <div class="todo">
            <p>{{ todo['content'] }} <i>({{ todo['degree']}})</i></p>
            <form method="POST" action="{{ url_for('delete', id=todo['_id']) }}" >
                <input type="submit" value="Delete Todo"
                       onclick="return confirm('Are you sure you want to delete this entry?')">
            </form>
        </div>
    {% endfor %}

保存并关闭文件。

在这里,您有一个向 delete() 视图函数提交 POST 请求的 Web 表单。 您通过 todo['_id'] 来指定将被删除的待办事项。 您可以使用 Web 浏览器中可用的 confirm() 方法在提交请求之前显示确认消息。

现在刷新您的索引页面,您将在每个待办事项下方看到一个 Delete Todo 按钮。 单击它,然后确认删除。 您将被重定向到索引页面,待办事项将不再存在。

您现在可以在 Flask 应用程序中从 mongoDB 数据库中删除不需要的待办事项。

要确认删除,请打开您的 mongo shell 并使用 find() 函数:

db.todos.find()

您应该会看到已删除的项目不再在您的 todos 集合中。

结论

您构建了一个小型 Flask Web 应用程序,用于管理与 MongoDB 数据库通信的待办事项。 您学习了如何连接到 MongoDB 数据库服务器、创建存储一组文档的集合、将数据插入集合以及从集合中检索和删除数据。

如果您想了解更多关于 Flask 的信息,请查看 如何使用 Flask 系列创建网站中的其他教程。

有关 MongoDB 的更多信息,请参阅我们的 如何使用 MongoDB 管理数据系列教程。