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

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

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

Flask 是一个轻量级的 Python 网页框架,提供用于在 Python 语言中创建网页应用程序的有用的工具和功能。 MongoDB是一个通用、面向文档的 NoSQL数据库程序,使用 JSON - 类似的文档来存储数据。 与关系数据库中使用的表关系不同,JSON 类似的文档允许灵活和动态的方案,同时保持简单性。

在本教程中,您将构建一个小型Todo列表网页应用程序,展示如何使用PyMongo库,一个MongoDB数据库驱动程序,允许您在Python中与MongoDB数据库进行交互。

前提条件

步骤 1 – 设置 PyMongo 和 Flask

在此步骤中,您将安装 Flask 和 PyMongo 库。

當您的虛擬環境啟用時,使用「pip」來安裝 Flask 和 PyMongo:

1pip install Flask pymongo

一旦安装成功完成,您将在输出结束时看到一个类似于以下的行:

1[secondary_label Output]
2
3Successfully 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 服务器进行交互,创建数据库,然后创建一个集合来存储您的 todos。

当您的编程环境启用时,打开名为app.py的文件,在您的flask_app目录中进行编辑:

1nano app.py

此文件将从 Flask 和 PyMongo 库导入所需的类和助手. 您将与您的 MongoDB 服务器进行交互,以创建数据库并为 todos 创建集合。

 1[label flask_app/app.py]
 2from flask import Flask
 3from pymongo import MongoClient
 4
 5app = Flask(__name__)
 6
 7client = MongoClient('localhost', 27017)
 8
 9db = client.flask_db
10todos = db.todos

保存并关闭文件。

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

你导入的MongoClient,你使用它来创建一个MongoDB实例的客户端对象,称为客户端,它允许你连接和与你的MongoDB服务器进行交互。

<$>[注] 注:

强烈建议您通过遵循我们在 Ubuntu 20.04 上如何保护 MongoDB 的指南(https://andsky.com/tech/tutorials/how-to-secure-mongodb-on-ubuntu-20-04)上的指南来加强 MongoDB 安装的安全性。

一旦您在 MongoDB 中启用了身份验证,您需要在创建一个MongoClient()实例时通过额外的用户名密码参数:

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

美元

然后,您可以使用客户端实例创建一个名为flask_db的 MongoDB 数据库,并在名为db的变量中保存参考。

然后,您使用db变量在flask_db数据库中创建一个名为todos的集合。

在MongoDB中,数据库和集合被虚假地创建,这意味着即使你运行app.py文件,连与数据库相关的代码都不会真正执行,直到第一个文档被创建为止。您将创建一个小型的Flask应用程序,其中有一个页面,允许用户在下一步中将 todo 文档插入您的todos集合中。一旦添加了第一个 todo 文档,您的 MongoDB 服务器上将创建flask_db数据库和todos集合。

若要获取当前数据库的列表,请打开新终端,并使用以下命令启动mongo壳:

1mongo

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

1show dbs

如果这是MongoDB的新安装,输出将列出admin,config本地数据库。

您会注意到flask_db尚不存在,然后在终端窗口中运行mongo壳,然后继续到下一步。

步骤 3 — 创建一个添加和显示全部的网页

在此步骤中,您将创建一个具有 Web 表单的 Web 页面,允许用户添加 Todos,并在同一页面上显示它们。

随着您的编程环境启用,打开您的 app.py 文件进行编辑:

1nano app.py

首先,从flask中添加以下进口:

1[label flask_app/app.py]
2from flask import Flask, render_template, request, url_for, redirect
3from pymongo import MongoClient
4
5# ...

在这里,您导入将用于渲染HTML模板的render_template()辅助函数,用户将提交的数据访问的请求对象, URL 生成的url_for()函数和redirect()函数,在添加 todo后将用户重定向回索引页面。

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

1[label flask_app/app.py]
2# ...
3
4@app.route('/', methods=('GET', 'POST'))
5def index():
6    return render_template('index.html')

保存并关闭文件。

在此路径中,您将GET,POST字符串转移到方法参数,以允许 GET 和 POST 请求。 GET 请求用于从服务器中获取数据。 POST 请求用于将数据发送到特定路径。默认情况下,仅允许 GET 请求。当用户先使用 GET 请求请求的 / 路径时,将生成一个名为 index.html 的模板文件。当用户填写并提交 Web 表格创建新 todos时,您将稍后编辑此路线以处理 POST 请求。

接下来,在您的flask_app目录中创建一个模板文件夹,以及您在前一条路径中提到的index.html模板:

1mkdir templates
2nano templates/index.html

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

 1[label flask_app/templates/index.html]
 2<!DOCTYPE html>
 3<html lang="en">
 4<head>
 5    <meta charset="UTF-8">
 6    <title>FlaskApp</title>
 7    <style>
 8        .todo {
 9            padding: 20px;
10            margin: 10px;
11            background-color: #eee;
12        }
13    </style>
14</head>
15<body>
16    <h1>FlaskTODO</h1>
17    <hr>
18    <div class="content">
19    <form method="post">
20        <p>
21            <b><label for="content">Todo content</label></b>
22        </p>
23        <p>
24            <input type="text" name="content"
25                placeholder="Todo Content"></input>
26        </p>
27
28        <p>
29            <b><label for="degree">Degree</label></b>
30        </p>
31        <p>
32            <input id="degree-0" name="degree" required type="radio" value="Important">
33            <label for="degree-0">Important</label>
34        </p>
35        <p>
36            <input id="degree-1" name="degree" required type="radio" value="Unimportant">
37            <label for="degree-1">Unimportant</label>
38        </p>
39        <button type="submit">Submit</button>
40    </form>
41    </div>
42</body>
43</html>

保存并关闭文件。

在 Web 表单中,您将方法属性设置为发布,以表示表单将提交 POST 请求。您有一个名为内容的 todo 内容的文本输入字段,您将使用它来访问您的/路径中的标题数据。您还具有两个名为级别的 HTML 广播按钮,允许用户指定每个 todo 项目的重要程度:他们可以在创建 todo 时选择 重要不重要选项。

在您的flask_app目录中启用虚拟环境时,请使用FLASK_APP环境变量告诉Flask关于该应用程序(在这种情况下是app.py) 然后将FLASK_ENV环境变量设置为development,以便在开发模式下运行应用程序并获取调试器的访问。有关Flask调试器的更多信息,请参阅如何处理Flask应用程序中的错误(LINK0)。

1export FLASK_APP=app
2export FLASK_ENV=development

接下来,运行应用程序:

1flask run

<$>[注] 注: 在尝试运行应用程序时,您可能会收到一个 ModuleNotFoundError: No module named 'pymongo' 错误。

当开发服务器运行时,请使用您的浏览器访问以下URL:

1http://127.0.0.1:5000/

您将看到索引页面,其中包含 Todo 内容的输入字段、重要程度的两个无线电按钮以及一个 ** Submit** 按钮。

The Index Page

有关 Web 表单的更多信息,请参阅 如何在 Flask 应用程序中使用 Web 表单。 有关管理 Web 表单的更先进和更安全的方法,请参阅 如何使用和验证 Web 表单使用 Flask-WTF

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

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

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

1nano app.py

编辑/路线以显示如下:

 1[label flask_app/app.py]
 2
 3@app.route('/', methods=('GET', 'POST'))
 4def index():
 5    if request.method=='POST':
 6        content = request.form['content']
 7        degree = request.form['degree']
 8        todos.insert_one({'content': content, 'degree': degree})
 9        return redirect(url_for('index'))
10
11    all_todos = todos.find()
12    return render_template('index.html', todos=all_todos)

保存并关闭文件。

在这些更改中,您处理if request.method ==POST``条件内的 POST 请求,您从request.form对象中提交的 todo 内容和重要程度。

您在 Python 字典中提供 todo 数据,将内容设置为用户在 todo 内容文本中提交的值,并将键设置为用户选择的无线电按钮的值。

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

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

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

1use flask_db

然后使用find()函数来获取数据库中的所有 todo 项目:

1db.todos.find()

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

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

1nano templates/index.html

通过在表单后添加一个 <hr> 间断和一个 Jinja for 循环来编辑文件,使文件看起来如下:

 1[label flask_app/templates/index.html]
 2<!DOCTYPE html>
 3<html lang="en">
 4<head>
 5    <meta charset="UTF-8">
 6    <title>FlaskApp</title>
 7    <style>
 8        .todo {
 9            padding: 20px;
10            margin: 10px;
11            background-color: #eee;
12        }
13    </style>
14</head>
15<body>
16    <h1>FlaskTODO</h1>
17    <hr>
18    <div class="content">
19    <form method="post">
20        <p>
21            <b><label for="content">Todo content</label></b>
22        </p>
23        <p>
24            <input type="text" name="content"
25                placeholder="Todo Content"></input>
26        </p>
27
28        <p>
29            <b><label for="degree">Degree</label></b>
30        </p>
31        <p>
32            <input id="degree-0" name="degree" required type="radio" value="Important">
33            <label for="degree-0">Important</label>
34        </p>
35        <p>
36            <input id="degree-1" name="degree" required type="radio" value="Unimportant">
37            <label for="degree-1">Unimportant</label>
38        </p>
39        <button type="submit">Submit</button>
40    </form>
41    <hr>
42    {% for todo in todos %}
43        <div class="todo">
44            <p>{{ todo['content'] }} <i>({{ todo['degree']}})</i></p>
45        </div>
46    {% endfor %}
47
48    </div>
49</body>
50</html>

保存并关闭文件。

在此文件中,您添加一个<hr>标签来分离网页表单和 todos列表。

您在行中使用for循环{% for todo in todos %}来浏览todos列表中的每个 todo 项目. 您在<p>标签中显示 todo 内容和重要程度。

现在更新您的索引页面,填写网页表格,并提交它. 您将看到您在表单下添加的 todo. 接下来,您将添加一个按钮,允许用户删除现有的 todos。

步骤 4 - 删除所有

在此步骤中,您将添加一条路线,允许用户使用按钮删除 todos。

首先,您将添加一个新的/id/delete路径,该路径接受 POST 请求. 您的新的delete()视图函数将收到从 URL 删除的 todo ID,然后使用该 ID 删除它。

要删除一个 todo,你将其 ID 作为一个字符串,你必须将其转换为 ObjectId,然后将其传输到收藏的删除方法,所以你需要从处理BSON(二进制JSON)编码和解码的 bson模块中导入 ObjectId()类。

打开app.py来编辑:

1nano app.py

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

1[label flask_app/app.py]
2from bson.objectid import ObjectId
3
4# ...

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

然后在末尾添加以下路线:

1[label flask_app/app.py]
2
3# ...
4
5@app.post('/<id>/delete/')
6def delete(id):
7    todos.delete_one({"_id": ObjectId(id)})
8    return redirect(url_for('index'))

保存并关闭文件。

在这里,您使用的是 Flask 版本 2.0.0中引入的 app.post]([Flask 版本 2.0.0])(https://flask.palletsprojects.com/en/2.0.x/changes/#version-2-0-0)),它为常见的 HTTP 方法添加了捷径,例如, @app.post("/login")' 是 @app.route("/login", methods=["POST"])' 的捷径,这意味着此视图只接受 POST 请求,并且在您的浏览器上导航到 /ID/delete 路径将返回 405 方法不允许 错误,因为 Web 浏览器默认为 GET 请求。 为了删除 todo,用户点击发送 POST 请求到该路

该函数接收要删除的 todo 文档的 ID. 您将该 ID 传输到 todos 集合中的 delete_one() 方法,并使用您之前导入的 ObjectId() 类将您接收的 string ID 转换为 ObjectId。

删除 todo 文档后,您将用户重定向到索引页面。

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

1nano templates/index.html

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

 1[label flask_app/templates/index.html]
 2
 3    {% for todo in todos %}
 4        <div class="todo">
 5            <p>{{ todo['content'] }} <i>({{ todo['degree']}})</i></p>
 6            <form method="POST" action="{{ url_for('delete', id=todo['_id']) }}" >
 7                <input type="submit" value="Delete Todo"
 8                       onclick="return confirm('Are you sure you want to delete this entry?')">
 9            </form>
10        </div>
11    {% endfor %}

保存并关闭文件。

在这里,你有一个网页表格,将POST请求提交到删除()视图函数中。 您通过todo['_id']来指定将被删除的 todo。 您使用在网页浏览器中可用的 confirm()方法在提交请求之前显示确认消息。

现在刷新你的索引页面,你会看到一个 删除 Todo按钮在每个 Todo 项目下面. 点击它,并确认删除。

现在你有办法从你的mongoDB数据库中删除不必要的 todos在你的Flask应用程序。

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

1db.todos.find()

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

结论

你建立了一个小型的 Flask Web 应用程序来管理与 MongoDB 数据库通信的 todos. 你学会了如何连接到 MongoDB 数据库服务器,创建存储一组文档的集合,将数据插入到集合中,并从集合中获取和删除数据。

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

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

Published At
Categories with 技术
comments powered by Disqus