如何在Flask应用程序中使用SQLite数据库

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

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

介绍

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

Flask 是一个轻量级的 Python Web 框架,它为使用 Python 语言创建 Web 应用程序提供了有用的工具和功能。 SQLite是一个简单快速的开源SQL引擎,可以与Python一起使用来存储和操作应用程序数据。 SQLite 与 Python 配合得很好,因为 Python 标准库提供了 sqlite3 模块,您可以使用它与任何 SQLite 数据库进行交互,而无需安装任何东西。 与其他数据库引擎相比,在 Python 中使用 SQLite 还需要最少的设置。

在本教程中,您将构建一个小型 Web 应用程序,演示如何使用 SQLite 和 Flask 执行基本的数据操作,包括 CRUD:创建、读取、更新和删除。 Web 应用程序将是一个在索引页面上显示帖子的基本博客。 用户可以创建、编辑和删除单个帖子。

先决条件

第 1 步 — 设置数据库

在此步骤中,您将设置用于存储数据(应用程序的博客文章)的 SQLite 数据库。 然后,您将使用一些示例条目填充数据库。

您将使用 sqlite3 模块与数据库进行交互,该模块在标准 Python 库中很容易获得。

SQLite 中的数据存储在表和列中,因此您首先需要创建一个名为 posts 的表,其中包含必要的列。 您将创建一个 .sql 文件,其中包含 SQL 命令以创建具有几列的 posts 表。 然后,您将使用此 模式文件 来创建数据库。

flask_app 目录中打开一个名为 schema.sql 的数据库模式文件:

nano schema.sql

在此文件中键入以下 SQL 命令:

flask_app/schema.sql

DROP TABLE IF EXISTS posts;

CREATE TABLE posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    title TEXT NOT NULL,
    content TEXT NOT NULL
);

保存并关闭文件。

在此模式文件中,首先删除 posts 表(如果它已存在)。 这避免了存在另一个名为 posts 的表的可能性,这可能会导致令人困惑的行为(例如,如果它具有不同的列)。 这里不是这样,因为你还没有创建表,所以不会执行 SQL 命令。 请注意,每当您执行此架构文件时,这将删除所有现有数据。 出于我们的目的,您将只执行此模式一次,但您可能希望再次执行它以删除您插入的任何数据并再次从一个空数据库开始。

接下来,您使用 CREATE TABLE posts 创建具有以下列的 posts 表:

  • id:表示主键的整数。 数据库将为每个条目(即每个博客文章)分配一个唯一值。 AUTOINCREMENT 自动增加帖子 ID,因此第一个帖子的 ID 为 1,之后添加的帖子的 ID 为 2,以此类推. 即使删除了其他帖子,每个帖子也将始终具有相同的 ID。
  • created:博文的创建时间。 NOT NULL 表示此列不能为空,DEFAULT 的值为 CURRENT_TIMESTAMP 的值,即帖子被添加到数据库的时间。 就像 id 一样,您不需要为此列指定值,因为它会自动填充。
  • title:帖子标题。 NOT NULL 表示该列不能为空。
  • content:帖子内容。 NOT NULL 表示该列不能为空。

现在,您将使用 schema.sql 文件来创建数据库。 为此,您将创建一个 Python 文件,该文件将基于此 schema.sql 文件生成 SQLite .db 数据库文件。 在 flask_app 目录中打开一个名为 init_db.py 的文件:

nano init_db.py

向其中添加以下代码:

烧瓶应用程序/init_db.py

import sqlite3

connection = sqlite3.connect('database.db')


with open('schema.sql') as f:
    connection.executescript(f.read())

cur = connection.cursor()

cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
            ('First Post', 'Content for the first post')
            )

cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
            ('Second Post', 'Content for the second post')
            )

connection.commit()
connection.close()

首先导入 sqlite3 模块。 您打开一个与名为 database.db 的数据库文件的连接,该文件将在您运行 Python 文件后创建。 然后使用 open() 函数打开 schema.sql 文件。 接下来,您使用 executescript() 方法执行其内容,该方法一次执行多个 SQL 语句,这将创建 posts 表。 您创建一个 Cursor 对象,它允许您处理数据库中的行。 在这种情况下,您将使用游标的 execute() 方法执行两个 INSERT SQL 语句,以将两个博客文章添加到您的 posts 表中。 最后,您提交更改并关闭连接。

保存并关闭文件,然后在终端中使用 python 命令运行它:

python init_db.py

一旦文件完成执行,一个名为 database.db 的新文件将出现在您的 flask_app 目录中。 这意味着您已成功设置数据库。

接下来,您将创建一个小型 Flask 应用程序,检索您插入数据库的两个帖子,并将它们显示在索引页面上。

第 2 步 - 显示帖子

在这一步中,您将创建一个带有索引页面的 Flask 应用程序,其中显示了您在数据库中的博客文章。

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

nano app.py

该文件将设置您的数据库连接并创建一个单一的 Flask 路由来使用该连接。 将以下代码添加到文件中:

烧瓶应用程序/app.py

import sqlite3
from flask import Flask, render_template

app = Flask(__name__)

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn


@app.route('/')
def index():
    conn = get_db_connection()
    posts = conn.execute('SELECT * FROM posts').fetchall()
    conn.close()
    return render_template('index.html', posts=posts)

保存并关闭文件。

在上面的代码中,您首先导入 sqlite3 模块以使用它连接到您的数据库。 然后从 flask 包中导入 Flask 类和 render_template() 函数。 你创建了一个名为 app 的 Flask 应用程序实例。 您定义了一个名为 get_db_connection() 的函数,它打开与您之前创建的 database.db 数据库文件的连接,并将 row_factory 属性设置为 sqlite3.Row可以对列进行基于名称的访问。 这意味着数据库连接将返回行为类似于常规 Python 字典的行。 最后,该函数返回您将用于访问数据库的 conn 连接对象。

然后你使用 app.route() 装饰器创建一个名为 index()Flask 视图函数。 您使用 get_db_connection() 函数打开数据库连接。 然后执行 SQL 查询以从 posts 表中选择所有条目。 您使用 fetchall() 方法获取查询结果的所有行,这将返回您在上一步中插入数据库的帖子列表。

您使用 close() 方法关闭数据库连接并返回渲染 index.html 模板的结果。 您还将 posts 对象作为参数传递,其中包含您从数据库中获得的结果。 这将允许您访问 index.html 模板中的博客文章。

要在索引页面上显示您在数据库中的帖子,您将首先创建一个基本模板,该模板将包含其他模板也将使用的所有基本 HTML 代码,以避免代码重复。 然后,您将创建在 index() 函数中呈现的 index.html 模板文件。 要了解有关模板的更多信息,请参阅 如何在 Flask 应用程序中使用模板

创建一个模板目录,然后打开一个名为 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>
        .post {
            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 %} Posts {% endblock %}</h1>
    {% for post in posts %}
        <div class='post'>
            <p>{{ post['created'] }}</p>
            <h2>{{ post['title'] }}</h2>
            <p>{{ post['content'] }}</p>
        </div>
    {% endfor %}
{% endblock %}

保存并关闭文件。

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

您在 {% for post in posts %} 行中使用 Jinja for loop 来浏览 posts 列表中的每个帖子。 您可以通过{{ post['created'] }}访问创建日期,通过{{ post['title'] }}访问标题,通过{{ post['content'] }}访问帖子内容。

在激活虚拟环境的 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/

您将在第一次启动时看到您添加到数据库中的帖子。

您已经在索引页面上显示了数据库中的帖子。 您现在需要允许用户添加新帖子。 您将在下一步中添加用于添加帖子的新路线。

第 3 步 - 创建帖子

在这一步中,您将向 Flask 应用程序添加一个新路由,该路由允许用户将新博客文章添加到数据库,然后将出现在索引页面上。

您将添加一个带有 Web 表单的页面,用户可以在其中输入帖子标题和帖子内容。 将验证此表单以确保用户不会提交空表单。 为了通知用户表单无效,您将使用 闪烁消息 ,它只会显示一次,并且会在下一次请求时消失(例如,如果您导航到另一个页面)。

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

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

nano app.py

为了处理 web 表单,你需要从 flask 包中导入一些东西:

  • 访问提交数据的全局 request 对象。
  • url_for() 函数用于生成 URL。
  • flash() 函数在请求无效时闪烁消息。
  • redirect() 函数将用户添加到数据库后重定向到索引页面。

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

烧瓶应用程序/app.py

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

# ...

flash() 函数将闪过的消息存储在客户端的浏览器会话中,这需要设置 密钥 来保护会话,从而记住从一个请求到另一个请求的信息。 您绝不能允许任何人访问您的密钥。 有关详细信息,请参阅 Flask 会话文档

通过 app.config 对象向您的应用程序添加 SECRET_KEY 配置来设置 密钥 。 将其添加到 app 实例定义旁边。

烧瓶应用程序/app.py

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

请记住,密钥应该是一个长的随机字符串。 有关 Web 表单和密钥配置的更多信息,请参阅 如何在 Flask 应用程序中使用 Web 表单

接下来,在 app.py 文件末尾添加以下路由:

烧瓶应用程序/app.py

# ...

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

保存并关闭文件。

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

打开新的 create.html 模板:

nano templates/create.html

向其中添加以下代码:

flask_app/templates/create.html

{% extends 'base.html' %}

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

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

保存并关闭文件。

您扩展基本模板,将标题设置为标题,并使用 <form> 标记并将属性 method 设置为 post 以指示表单将提交 POST 请求. 您有一个名称为 title 的文本字段,您将使用它来访问 /create 路由中的标题数据。 如果表单无效,您将文本字段的值设置为 request.form['title'] 或者为空或保存的标题版本,以便在出现问题时标题不会丢失。

在标题输入字段之后,添加一个名为 content 的文本区域,其值为 {{ request.form['content'] }} 以在表单无效时恢复帖子内容。

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

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

http://127.0.0.1:5000/create

您将看到一个 Add a New Post 页面,其中包含帖子标题的输入字段、帖子内容的文本区域和 Submit 按钮。

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

打开 app.py 处理用户提交的 POST 请求:

nano app.py

编辑 /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:
            conn = get_db_connection()
            conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
                         (title, content))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('create.html')

保存并关闭文件。

您在 if request.method == 'POST' 条件内处理 POST 请求。 您从 request.form 对象中提取用户提交的标题和内容。 如果标题为空,则使用 flash() 功能闪烁消息 Title is required!。 如果内容为空,您也可以这样做。

如果同时提供了标题和内容,则使用 get_db_connection() 函数打开数据库连接。 您使用 execute() 方法执行 INSERT INTO SQL 语句以将新帖子添加到 posts 表,其中包含用户提交的标题和内容作为值。 您使用 ? 占位符将数据安全地插入到表中。 您提交事务并关闭连接。 最后,您将用户重定向到索引页面,在那里他们可以在现有帖子下方看到他们的新帖子。

警告: 切勿使用 Python 字符串操作来动态创建 SQL 语句字符串。 始终在 SQL 语句中使用 ? 占位符来动态替换值。 将值元组作为第二个参数传递给 execute() 方法,以将您的值绑定到 SQL 语句。 这可以防止 SQL 注入攻击


在开发服务器运行的情况下,使用浏览器导航到 /create 路由:

http://127.0.0.1:5000/create

填写表格并提交。

您将被重定向到您将看到新帖子的索引页面。

如果您提交的表单没有标题或没有任何内容,您的帖子将不会被添加到数据库中,您不会被重定向到索引页面,您也不会收到任何反馈。 这是因为您尚未设置要在任何地方显示的闪现消息。

打开 base.html 在导航栏中添加指向创建页面的链接,并在其下方显示闪烁的消息。

nano templates/base.html

编辑该文件,如下所示:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .post {
            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>

保存并关闭文件。

在这里,您将新的 <a> 链接添加到指向“创建”页面的导航栏。

您使用 Jinja for 循环来浏览闪烁的消息。 这些在 get_flashed_messages() 特殊功能中可用。 每条消息都显示在 <div> 标记中,带有一个名为 alert 的 CSS 类。 您可以在 <head> 部分的 <style> 标记内设置此 <div> 标记的样式。

刷新您的索引页面,您将在导航栏中看到新链接。

单击 Create 链接,然后提交一个空表单。 您将收到闪现的消息“Title is required!”

填写标题字段并将内容文本区域留空。 再次提交表单,您将收到“需要内容!” 信息。 注意“标题是必需的!” 消息不见了。 这是因为它是 闪现消息 而不是永久消息。

您现在可以添加新帖子了。 接下来,您将添加一条允许用户编辑现有帖子的新路线。

第 4 步 - 编辑帖子

在此步骤中,您将向应用程序添加一条新路由,以允许用户编辑现有帖子。

首先,为了避免代码重复并隔离代码并使其更易于维护,您将添加一个新函数,该函数接受一个 ID 并从数据库中检索与其关联的帖子。 您将使用此功能获取要编辑的帖子数据,并在下一步中使用它来获取要删除的帖子。

打开app.py

nano app.py

如果请求的帖子的 ID 与任何现有帖子都不对应,则用于检索帖子的函数将响应 404 Not Found 错误。 为此,您将使用 abort() 函数,该函数中止请求并以错误消息响应。 有关更多信息,请参阅 如何处理 Flask 应用程序中的错误

abort() 函数添加到导入:

烧瓶应用程序/app.py

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

get_db_connection() 函数下方添加一个名为 get_post() 的新函数:

烧瓶应用程序/app.py

# ...

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn

def get_post(post_id):
    conn = get_db_connection()
    post = conn.execute('SELECT * FROM posts WHERE id = ?',
                        (post_id,)).fetchone()
    conn.close()
    if post is None:
        abort(404)
    return post

# ...

这个新函数有一个 post_id 参数,用于确定要检索和返回的帖子。 您使用 get_db_connection() 打开数据库连接并执行 SQL 查询以获取与给定 post_id 值关联的帖子。 您使用 fetchone() 方法获取帖子,将其存储在 post 变量中,然后关闭连接。

如果 post 变量的值为 None,这意味着在数据库中没有找到结果,则使用之前导入的 abort() 函数以 [X170X ] 错误代码,函数将完成执行。 但是,如果找到帖子,则返回 post 变量的值。

接下来,在文件末尾添加一条用于编辑帖子的新路径:

烧瓶应用程序/app.py

# ...

@app.route('/<int:id>/edit/', methods=('GET', 'POST'))
def edit(id):
    post = get_post(id)

    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:
            conn = get_db_connection()
            conn.execute('UPDATE posts SET title = ?, content = ?'
                         ' WHERE id = ?',
                         (title, content, id))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('edit.html', post=post)

保存并关闭文件。

您使用路线 /<int:id>/edit/,其中 int: 是一个接受正整数的 转换器id 是 URL 变量,它将确定您要编辑的帖子。 例如,/2/edit/ 将允许您编辑 ID 为 2 的帖子。 ID 从 URL 传递到 edit() 视图函数。 您将 id 参数的值传递给 get_post() 函数,以从数据库中获取与提供的 ID 关联的帖子。 请记住,如果不存在具有给定 ID 的帖子,这将响应 404 Not Found 错误。

最后一行渲染一个名为 edit.html 的模板文件,并传入包含发布数据的 post 变量。 您将使用它在“编辑”页面上显示现有标题和内容。

if request.method == 'POST' 块处理用户提交的新数据。 与添加新帖子类似,您可以提取标题和内容。 如果未提供标题或内容,您会闪烁一条消息。

如果表单有效,则打开数据库连接,使用UPDATE SQL 语句通过设置新标题和新内容来更新posts 表,其中数据库中帖子的ID等于 URL 中的 ID。 您提交事务、关闭连接并重定向到索引页面。

接下来,您需要创建一个用户可以在其中进行编辑的页面。 打开一个新的 edit.html 模板:

nano templates/edit.html

向其中添加以下代码:

flask_app/templates/edit.html

{% extends 'base.html' %}

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

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

保存并关闭文件。

这类似于 create.html 模板中的代码,除了在 {% block title %} Edit "{{ post['title'] }}" {% endblock %} 行中的页面标题内显示帖子标题,在 {{ request.form['title'] or post['title'] }} 中输入的值,以及{{ request.form['content'] or post['content'] }}中文本区域的值。 这将显示存储在请求中的数据(如果存在); 否则它将显示来自 post 变量的数据,该变量已传递给包含当前数据库数据的模板。

在开发服务器运行的情况下,使用浏览器导航到以下 URL 以编辑第一篇文章:

http://127.0.0.1:5000/1/edit

您将看到如下所示的页面:

编辑帖子并提交表格。 您将在索引页面上看到应用的更改。 如果您提交的表单没有标题或没有任何内容,您将收到一条闪现的消息。

您现在需要为索引页面上的每个帖子添加一个指向编辑页面的链接。 打开index.html模板文件:

nano templates/index.html

编辑该文件,使其与以下内容完全相同:

flask_app/templates/index.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Posts {% endblock %}</h1>
    {% for post in posts %}
        <div class='post'>
            <p>{{ post['created'] }}</p>
            <h2>{{ post['title'] }}</h2>
            <p>{{ post['content'] }}</p>
            <a href="{{ url_for('edit', id=post['id']) }}">Edit</a>
        </div>
    {% endfor %}
{% endblock %}

保存并关闭文件。

您添加了链接到 edit() 视图函数的 <a> 标记。 您将 post['id']) 中的帖子 ID 传递给 url_for() 函数以生成帖子的编辑链接。 这会添加一个指向其下方每个帖子的编辑页面的链接。

刷新索引页面,点击编辑链接编辑帖子。

您现在可以添加新帖子并编辑现有帖子。 接下来,您将添加一个按钮以允许用户删除现有帖子。

第 5 步 — 删除帖子

在此步骤中,您将向编辑页面添加一个删除按钮,以允许用户删除帖子。

首先,您将添加一个接受 POST 请求的新 /id/delete 路由,类似于 edit() 视图函数。 您的新 delete() 视图函数将从 URL 中接收要删除的帖子的 ID,使用 get_post() 函数检索它,然后从数据库中删除它(如果存在)。

打开app.py文件:

nano app.py

在末尾添加以下路由:

烧瓶应用程序/app.py

# ...

@app.route('/<int:id>/delete/', methods=('POST',))
def delete(id):
    post = get_post(id)
    conn = get_db_connection()
    conn.execute('DELETE FROM posts WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    flash('"{}" was successfully deleted!'.format(post['title']))
    return redirect(url_for('index'))

保存并关闭文件。

此视图函数仅接受 methods 参数中的 POST 请求。 这意味着在浏览器上导航到 /ID/delete 路由将返回 405 Method Not Allowed 错误,因为 Web 浏览器默认使用 GET 请求。 要删除帖子,用户单击向该路由发送 POST 请求的按钮。

该函数接收要删除的帖子的 ID。 您可以使用此 ID 通过 get_post() 函数检索帖子。 如果不存在具有给定 ID 的帖子,则会返回 404 Not Found 错误。 您打开一个数据库连接并执行 DELETE FROM SQL 命令来删除帖子。 您使用 WHERE id = ? 指定要删除的帖子。

您将更改提交到数据库并关闭连接。 您闪烁一条消息以通知用户该帖子已成功删除并将他们重定向到索引页面。

请注意,您不会呈现模板文件。 这是因为您只需将删除按钮添加到编辑页面。

打开edit.html模板文件:

nano templates/edit.html

然后在 {% endblock %} 行之前直接添加以下 <hr><form> 标签:

flask_app/templates/edit.html

        <button type="submit">Submit</button>
    </form>


    <hr>
    <form action="{{ url_for('delete', id=post['id']) }}" method="POST">
        <input type="submit" value="Delete Post"
                onclick="return confirm('Are you sure you want to delete this post?')">
    </form>
{% endblock %}

保存并关闭文件。

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

现在再次导航到帖子的编辑页面并尝试删除它:

http://127.0.0.1:5000/1/edit

确认删除后,您将被重定向到索引页面,并且该帖子将不再存在。 导航栏下方将显示一条消息,通知您该帖子已成功删除。

您现在可以在 Flask 应用程序的数据库中删除不需要的帖子。

结论

您构建了一个与 SQLite 数据库通信的小型网络博客。 您的 Flask 应用程序具有基本功能,例如向数据库添加新数据、检索数据并将其显示在页面上,以及编辑和删除现有数据。

有关如何在 Python 和 Flask 中使用 SQLite 的更多信息,请参阅以下教程:

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