作者选择自由和开源基金作为Write for DOnations计划的一部分来接受捐赠。

简介

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

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

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

先决条件

  • 本地 Python 3 编程环境,按照如何为 Python 3系列安装和设置本地编程环境中的教程进行分发。在本教程中,我们将调用我们的项目目录flask_app

  • MongoDB 安装在本地机器上。按照如何在 Ubuntu 20.04 上安装 MongoDB 指南设置您的 MongoDB 数据库。

  • 了解基本的 Flask 概念,例如路由、视图函数和模板。如果您不熟悉 Flask,请查看如何使用 Flask 和 Python 创建您的第一个 Web 应用程序和如何在 Flask 应用程序中使用模板。

  • 了解基本的 HTML 概念。您可以查看我们的如何使用 HTML 构建网站教程系列以了解背景知识。

第一步——设置 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 服务器并创建一个集合。

第二步——连接MongoDB服务器并创建集合

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

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

nano app.py

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

烧瓶_app/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 应用程序,该页面允许用户在下一步中将 todo 文档插入到您的todos集合中。添加第一个 todo 文档后,flask_db数据库和todos集合将在您的 MongoDB 服务器上创建。

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

mongo

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

show dbs

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

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

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

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

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

nano app.py

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

烧瓶_app/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/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文件中添加以下代码:

烧瓶_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 选项或 Unimportant 选项.最后,表单末尾有一个 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/

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

索引页

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

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

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

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

nano app.py

编辑/路由,如下所示:

烧瓶_app/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 字典中提供 todo 数据,将'content'设置为用户在 todo 内容的文本字段中提交的值,并将'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>中断和Jinjafor循环,使文件如下所示:

烧瓶_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>标签内显示待办事项内容和重要程度。

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

第四步——删除待办事项

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

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

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

打开app.py进行编辑:

nano app.py

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

烧瓶_app/app.py

from bson.objectid import ObjectId

# ...

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

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

烧瓶_app/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循环:

烧瓶_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 zwz100187 '_id']指定将被删除的待办事项。在提交请求之前,您可以使用 Web 浏览器中可用的 confirm()方法显示确认消息。

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

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

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

db.todos.find()

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

结论

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

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

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

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐