如何使用 Python 3 中的 Flask 制作网络应用程序

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

介绍

Flask是一个小而轻量级的Python网络框架,提供有用的工具和功能,使在Python中创建Web应用程序更容易。它为开发人员提供了灵活性,并且是新的开发者更容易访问的框架,因为您可以使用单个Python文件快速构建Web应用程序。

作为本教程的一部分,您将使用Bootstrap工具包(https://getbootstrap.com/)来设计您的应用程序,使其更具视觉吸引力。Bootstrap将帮助您将响应式网页纳入您的Web应用程序,以便它在移动浏览器上也很好地工作,而无需写自己的HTML,CSS和JavaScript代码来实现这些目标。

Flask 使用 Jinja 模板引擎以动态地使用熟悉的 Python 概念构建 HTML 页面,如变量、循环、列表等。

在本教程中,您将使用Python中的Flask和SQLite(https://sqlite.org)构建一个小型网页博客。应用程序的用户可以查看您的数据库中的所有帖子,然后点击帖子的标题,以查看其内容,并在数据库中添加新帖子,并编辑或删除现有帖子。

<$>[info] 简化使用 DigitalOcean App Platform的Flask应用程序的部署。

前提条件

在你开始遵循这个指南之前,你将需要:

步骤一:安装瓶子

在此步骤中,您将激活 Python 环境并使用 pip包安装程序安装 Flask。

如果您尚未激活您的编程环境,请确保您位于项目目录中(‘flask_blog’),并使用以下命令激活环境:

1source env/bin/activate

一旦您的编程环境被激活,您的提示现在将有一个env前缀,可以看起来如下:

此前缀表明环境env目前处于活跃状态,根据您在创建时如何命名,该环境可能有不同的名称。

注意:您可以使用 Git,一个版本控制系统,以有效地管理和跟踪您的项目的开发过程。

如果您正在使用 Git,最好在您的.gitignore 文件中忽略新创建的 env 目录,以避免跟踪与项目无关的文件。

现在您将安装 Python 包,并将项目代码从主要的 Python 系统安装中分离出来,您将使用pippython来完成此操作。

要安装 Flask,请执行以下命令:

1pip install flask

安装完成后,运行以下命令来确认安装:

1python -c "import flask; print(flask.__version__)"

您可以使用 python 命令行接口-c 选项来执行 Python 代码,然后导入 flask 包,然后打印 Flask 版本,这是通过 flask.__version__ 变量提供的。

输出将是一个类似于下列版本的版本号:

1[secondary_label Output]
21.1.2

您已经创建了项目文件夹、虚拟环境并安装了 Flask。

步骤二:创建基础应用程序

现在你已经设置了编程环境,你将开始使用Flask. 在这个步骤中,你将创建一个Python文件中的小型Web应用程序,并运行它来启动服务器,该服务器将在浏览器上显示一些信息。

在您的flask_blog目录中,打开名为hello.py的文件进行编辑,使用nano或您最喜欢的文本编辑器:

1nano hello.py

此「hello.py」文件将作为处理 HTTP 请求的最小示例。 里面,你将导入 Flask 对象,并创建一个返回 HTTP 响应的函数。 在「hello.py」里面写下以下代码:

1[label flask_blog/hello.py]
2from flask import Flask
3
4app = Flask(__name__)
5
6@app.route('/')
7def hello():
8    return 'Hello, World!'

在之前的代码块中,你首先从flask包中导入Flask对象,然后使用它来创建你的Flask应用程序实例,名为app。你通过了持有当前Python模块名称的特殊变量__name__

一旦你创建了app实例,你会使用它来处理到来的网页请求,并向用户发送响应。@app.route是将常规的Python函数转换为Flask _view函数,该函数的返回值转换为由HTTP客户端(如网页浏览器)显示的HTTP响应。

Hello()视图函数返回字符串Hello, World!作为响应。

保存并关闭文件。

要运行您的Web应用程序,您首先会告诉Flask在哪里找到应用程序(在您的情况下是hello.py文件)与FLASK_APP环境变量:

1export FLASK_APP=hello

然后在开发模式下运行它,使用FLASK_ENV环境变量:

1export FLASK_ENV=development

最后,使用flask run命令运行应用程序:

1flask run

一旦应用程序运行,输出将是这样的东西:

1[secondary_label Output]
2 * Serving Flask app "hello" (lazy loading)
3 * Environment: development
4 * Debug mode: on
5 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
6 * Restarting with stat
7 * Debugger is active!
8 * Debugger PIN: 813-894-335

上一个输出有几个信息,如:

  • 您正在运行的应用程序的名称.
  • 应用程序正在运行的环境.
  • Debug mode: on 意味着Flask 调试器正在运行. 这是在开发时有用的,因为它会给我们详细的错误消息,当事情发生错误时,这使得解决问题更容易。
  • 应用程序在URL上本地运行,http://127.0.0.1:5000/`, '127.0.0.1'是代表您的机器的 'localhost' 和 ':5000' 是端口号的 IP。

打开浏览器并键入URL http://127.0.0.1:5000/,您将收到字符串 Hello, World!作为回复,这确认您的应用程序正在成功运行。

<$>[警告] 警告 Flask 使用一个简单的 Web 服务器在开发环境中服务我们的应用程序,这也意味着 Flask 调试器正在运行,以便更容易捕捉错误。 该开发服务器不应该用于生产部署。 请参阅 Flask 文档上的 部署选项页面以获取更多信息,您也可以查看此 Flask 部署教程

现在,您可以离开开发服务器在终端中运行,然后打开另一个终端窗口。 移动到位于hello.py的项目文件夹,激活虚拟环境,设置环境变量FLASK_ENVFLASK_APP,然后继续到下一个步骤。

<$>[注] :在打开新终端时,重要的是要记住激活虚拟环境并设置环境变量 FLASK_ENVFLASK_APP

虽然 Flask 应用程序的开发服务器已经运行,但无法使用相同的 flask run 命令运行另一个 Flask 应用程序. 这是因为 flask run 默认使用的端口号码是 5000,一旦它被打开,它就无法运行另一个应用程序,因此您会收到类似以下的错误:

1[secondary_label Output]
2OSError: [Errno 98] Address already in use

要解决此问题,要么停止当前通过CTRL+C运行的服务器,然后再次运行flask run,要么如果要同时运行两个端口,可以将不同的端口号传递给-p参数,例如,要在端口5001上运行另一个应用程序,请使用以下命令:

1flask run -p 5001

美元

你现在有一个小型的FlaskWeb应用程序. 你已经运行了你的应用程序,并在Web浏览器上显示了信息。接下来,你将在你的应用程序中使用HTML文件。

第3步:使用HTML模板

目前,您的应用程序只显示一个简单的消息,没有任何HTML。Web应用程序主要使用HTML来显示信息给访问者,所以您现在将致力于将HTML文件纳入您的应用程序中,该文件可以在Web浏览器中显示。

Flask 提供一个 render_template() 辅助功能,允许使用 Jinja 模板引擎。这将通过在 .html 文件中写你的 HTML 代码以及使用你的 HTML 代码中的逻辑来更容易地管理 HTML。你将使用这些 HTML 文件(templates)来构建你的所有应用程序页面,例如你将显示当前博客帖子的主要页面,博客帖的页面,用户可以添加新帖子的页面等等。

在此步骤中,您将在新文件中创建您的主要 Flask 应用程序。

首先,在你的flask_blog目录中,使用nano或你最喜欢的编辑器来创建和编辑你的app.py文件。

1nano app.py

在这个新文件中,你将导入Flask对象来创建一个Flask应用程序实例,就像你以前一样。你还将导入render_template()(https://flask.palletsprojects.com/en/1.1.x/api/#flask.render_template)帮助函数,允许你在你要创建的模板文件夹中渲染存在的HTML模板文件。

1[label flask_blog/app.py]
2from flask import Flask, render_template
3
4app = Flask(__name__)
5
6@app.route('/')
7def index():
8    return render_template('index.html')

index()视图函数返回了以index.html为参数呼叫render_template()的结果,这告诉render_template()templates文件夹中搜索一个名为index.html的文件。 文件夹和文件都还不存在,如果你在这个时候运行应用程序,你会收到一个错误。

保存和退出文件。

在您的其他终端中停止开发服务器,该服务器以CTRL+C运行你好应用程序。

在运行应用程序之前,请确保正确指定环境变量FLASK_APP的值,因为您不再使用应用程序Hello:

1export FLASK_APP=app
2flask run

在您的浏览器中打开URL http://127.0.0.1:5000/将导致调试页面告知您没有找到template index.html 模板。 代码中的主要行将突出显示这个错误。 在这种情况下,它是‘return render_template('index.html')’。

如果您点击此行,调试程序将显示更多的代码,以便您有更多的背景,以帮助您解决问题。

The Flask Debugger

要修复此错误,请在您的flask_blog目录中创建名为模板的目录,然后在其内部打开名为index.html的文件以进行编辑:

1mkdir templates
2nano templates/index.html

接下来,在 index.html 中添加以下 HTML 代码:

 1[label flask_blog/templates/index.html]
 2<!DOCTYPE html>
 3<html lang="en">
 4<head>
 5    <meta charset="UTF-8">
 6    <title>FlaskBlog</title>
 7</head>
 8<body>
 9   <h1>Welcome to FlaskBlog</h1>
10</body>
11</html>

保存文件并使用您的浏览器再次导航到 http://127.0.0.1:5000/,或刷新页面. 此时,浏览器应该在一个 <h1> 标签中显示文本 Welcome to FlaskBlog

除了模板文件夹外,Flask Web 应用程序通常还具有用于托管静态文件的静态文件夹,例如 CSS 文件、JavaScript 文件和应用程序使用的图像。

您可以创建一个style.css风格表文件,将CSS添加到您的应用程序中,首先,在您的主要flask_blog目录中创建一个名为static的目录:

1mkdir static

然后在静态目录中创建另一个名为css的目录,以托管.css文件。这通常是为了在专用文件夹中组织静态文件,因此,JavaScript文件通常生活在名为js的目录中,图像被放入名为images(或img)的目录中,等等。

1mkdir static/css

然后在css目录中打开一个style.css文件来编辑:

1nano static/css/style.css

将以下 CSS 规则添加到您的 style.css 文件中:

1[label flask_blog/static/css/style.css]
2h1 {
3    border: 2px #eee solid;
4    color: brown;
5    text-align: center;
6    padding: 10px;
7}

CSS 代码将添加边界,将颜色更改为棕色,中心文本,并添加<h1>标签。

保存并关闭文件。

接下来,打开index.html模板文件进行编辑:

1nano templates/index.html

您将添加一个链接到style.css文件在index.html模板文件的<head>部分:

1[label flask_blog/templates/index.html]
2. . .
3<head>
4    <meta charset="UTF-8">
5    <link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}">
6    <title>FlaskBlog</title>
7</head>
8. . .

在这里,您使用 url_for() 辅助函数来生成文件的适当位置. 第一个参数表示您正在链接到静态文件,第二个参数是静态目录中的文件路径。

保存并关闭文件。

当您更新应用程序的索引页面时,您会注意到文本欢迎来到FlaskBlog现在是棕色,中心,并在边界中封闭。

但是,如果你不是网页设计师,或者如果你不熟悉CSS,那么你可以使用Bootstrap工具包(https://getbootstrap.com/),它为你的应用程序提供易于使用的元件。

您可能已经猜测,创建另一个 HTML 模板意味着重复您已经在 index.html 模板中写的大部分 HTML 代码. 您可以通过一个 base template 文件来避免不必要的代码重复,您所有的 HTML 文件都会继承。

要创建一个基础模板,首先在你的模板目录中创建一个名为base.html的文件:

1nano templates/base.html

在您的「base.html」模板中输入以下代码:

 1[label flask_blog/templates/base.html]
 2<!doctype html>
 3<html lang="en">
 4  <head>
 5    <!-- Required meta tags -->
 6    <meta charset="utf-8">
 7    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 8
 9    <!-- Bootstrap CSS -->
10    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
11
12    <title>{% block title %} {% endblock %}</title>
13  </head>
14  <body>
15    <nav class="navbar navbar-expand-md navbar-light bg-light">
16        <a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
17        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
18            <span class="navbar-toggler-icon"></span>
19        </button>
20        <div class="collapse navbar-collapse" id="navbarNav">
21            <ul class="navbar-nav">
22            <li class="nav-item active">
23                <a class="nav-link" href="#">About</a>
24            </li>
25            </ul>
26        </div>
27    </nav>
28    <div class="container">
29        {% block content %} {% endblock %}
30    </div>
31
32    <!-- Optional JavaScript -->
33    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
34    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
35    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
36    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
37  </body>
38</html>

保存并关闭文件,一旦完成编辑。

在前一块中大部分的代码是标准的HTML和Bootstrap所需的代码. <meta>标签为Web浏览器提供信息, <link>标签链接到Bootstrap CSS文件,而 <script>标签是链接到JavaScript代码,允许一些额外的Bootstrap功能。

但是,以下突出部分是Jinja模板引擎的特征:

  • {% block title %} {% endblock %}: 作为一个标题的位置持有人(https://jinja.palletsprojects.com/en/2.10.x/templates/#blocks)的区块,你以后会用它在其他模板中给你的应用程序中的每个页面一个自定义标题而不重写整个 <head> 部分每次。
  • { url_for('index')}}: 一个函数调用,将返回 URL for the index()视图函数. 这与以前的url_for()` 调用你用来链接一个静态 CSS 文件不同,因为它只需要一个参数,即视图函数的名称,并链接到与该函数相关的路径而不是静态文件。

现在你有一个基础模板,你可以利用继承来利用它。

1nano templates/index.html

然后将其内容替换为如下:

1[label flask_blog/templates/index.html]
2{% extends 'base.html' %}
3
4{% block content %}
5    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
6{% endblock %}

在这个index.html模板的新版本中,您使用{% extends %}标签来继承从base.html模板中。

这个内容块包含一个<h1>标签,在一个标题块中包含文本欢迎到FlaskBlog,这反过来会用文本欢迎到FlaskBlog代替base.html模板中的原始标题块。

模板继承还允许您在其他模板中重复使用HTML代码(在这种情况下是base.html),而无需每次重复使用。

保存和关闭文件,并在您的浏览器上更新索引页面. 您将看到您的页面与导航栏和风格的标题。

Index Page with Bootstrap

您已经在 Flask 中使用了 HTML 模板和静态文件,您还使用 Bootstrap 开始改进页面外观和基础模板,以避免代码重复。

步骤4:创建数据库

在此步骤中,您将设置一个数据库来存储数据,即您的应用程序的博客帖子。

您将使用 SQLite 数据库文件来存储您的数据,因为 sqlite3模块,我们将用来与数据库进行交互,可以在标准的 Python 库中找到。

首先,因为SQLite中的数据存储在表和列中,并且由于您的数据主要由博客帖子组成,您首先需要创建一个名为帖子的表,其中包含所需的列。

在您的「flask_blog」目錄中開啟名為「schema.sql」的檔案:

1nano schema.sql

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

1[label flask_blog/schema.sql]
2DROP TABLE IF EXISTS posts;
3
4CREATE TABLE posts (
5    id INTEGER PRIMARY KEY AUTOINCREMENT,
6    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
7    title TEXT NOT NULL,
8    content TEXT NOT NULL
9);

保存并关闭文件。

第一个 SQL 命令是DROP TABLE IF EXISTS posts;,这会删除任何已经存在的名为posts的表格,这样你就不会出现混淆的行为。 请注意,这将删除你在数据库中的所有内容,每次你使用这些 SQL 命令,所以确保你不会在 Web 应用程序中写任何重要的内容,直到你完成本教程并尝试最终结果。

  • id: 代表一个 primary key 的整数,这将被数据库分配给每个条目(即博客帖子)的唯一值。
  • created: 该博客帖创建时间在. NOT NULL 意味着该列不应该空,而 DEFAULT 值是 CURRENT_TIMESTAMP 值,即该帖子被添加到数据库的时间。

现在你在schema.sql文件中有一个 SQL 方案,你将使用它创建数据库,使用 Python 文件生成 SQLite `.db’ 数据库文件。

1nano init_db.py

然后添加以下代码。

 1[label flask_blog/init_db.py]
 2import sqlite3
 3
 4connection = sqlite3.connect('database.db')
 5
 6with open('schema.sql') as f:
 7    connection.executescript(f.read())
 8
 9cur = connection.cursor()
10
11cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
12            ('First Post', 'Content for the first post')
13            )
14
15cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
16            ('Second Post', 'Content for the second post')
17            )
18
19connection.commit()
20connection.close()

你首先导入sqlite3模块,然后打开一个连接到名为database.db的数据库文件,它将在运行Python文件后创建,然后使用open()函数打开schema.sql文件,然后使用executescript()(https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.executescript)方法执行其内容,同时执行多个SQL陈述,这将创建帖子表,然后创建一个Cursor object(https://docs.python.org/3/library/sqlite3.html#cursor-objects),允许你使用它的execute()(https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.execute)方法执行两个INSERTSQL陈述,将两个博客帖子添加到你的帖子表。

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

1python init_db.py

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

在下一步中,您将获取您插入数据库的帖子,并在应用程序的主页中显示它们。

步骤 5 - 显示所有帖子

现在你已经设置了数据库,你现在可以修改index()视图函数,以显示你在数据库中的所有帖子。

打开app.py文件以进行以下更改:

1nano app.py

对于您的第一个修改,您将导入文件顶部的 sqlite3 模块:

1[label flask_blog/app.py]
2import sqlite3
3from flask import Flask, render_template
4
5. . .

接下来,您将创建一个函数,创建数据库连接并返回它。

 1[label flask_blog/app.py]
 2. . .
 3from flask import Flask, render_template
 4
 5def get_db_connection():
 6    conn = sqlite3.connect('database.db')
 7    conn.row_factory = sqlite3.Row
 8    return conn
 9
10. . .

get_db_connection() 函数打开对 database.db 数据库文件的连接,然后将 row_factory 属性设置为 sqlite3.Row,以便您可以基于名称访问列。

定义get_db_connection()函数后,修改index()函数以显示如下:

1[label flask_blog/app.py]
2. . .
3
4@app.route('/')
5def index():
6    conn = get_db_connection()
7    posts = conn.execute('SELECT * FROM posts').fetchall()
8    conn.close()
9    return render_template('index.html', posts=posts)

在这个新版本的index()函数中,您首先使用您之前定义的get_db_connection()函数打开数据库连接,然后运行 SQL 查询,从帖子表中选择所有条目。

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

有了这些更改,保存并关闭app.py文件。

现在你已经将从数据库中提取的帖子传递到‘index.html’模板中,你可以使用一个 for loop来显示每个帖子在你的索引页面上。

打开index.html文件:

1nano templates/index.html

然后,修改它看起来如下:

 1[label flask_blog/templates/index.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
 6    {% for post in posts %}
 7        <a href="#">
 8            <h2>{{ post['title'] }}</h2>
 9        </a>
10        <span class="badge badge-primary">{{ post['created'] }}</span>
11        <hr>
12    {% endfor %}
13{% endblock %}

在这里,语法 {% for post in %}' 是一个 Jinja for循环,类似于 Pythonfor循环,但它必须后来用{% endfor %}' 语法关闭。你使用这个语法在字符串 index() 函数在行 return render_template('index.html', posts=posts)中通过的posts' 列表中的每个项目上循环。

您使用字面变量分界器({... }})显示标题。 请记住,帖子将是一个字典类似的对象,因此您可以使用帖子标题`访问帖子标题。

一旦你完成了编辑文件,保存并关闭它,然后导航到你的浏览器的索引页面,你会看到你在你的页面上添加到数据库的两个帖子。

Index Page with Posts Displayed

现在你已经修改了index()视图功能,以显示你在应用程序的主页上数据库中的所有帖子,你将继续以单一页面显示每个帖子,并允许用户链接到每个单独的帖子。

步骤 6 - 显示单个帖子

在此步骤中,您将创建一个新的Flask路线,具有视图功能和一个新的HTML模板,以通过其ID显示单个博客帖子。

在此步骤结束时,URL http://127.0.0.1:5000/1将是一个显示第一个帖子的页面(因为它具有ID 1)。

打开app.py来编辑:

1nano app.py

由于您将在本项目后期需要从数据库中从多个位置获取博客帖子以其ID,您将创建一个名为get_post()的独立函数,您可以通过将其称为ID并收到与所提供ID相关的博客帖子,或者让Flask以404 Not Found消息回复,如果博客帖子不存在。

要用「404」页面回复,您需要从安装在文件顶部的「Werkzeug(LINK1)」库中导入 abort()函数:

1[label flask_blog/app.py]
2import sqlite3
3from flask import Flask, render_template
4from werkzeug.exceptions import abort
5
6. . .

然后,在上一个步骤中创建的get_db_connection()函数之后,添加get_post()函数:

 1[label flask_blog/app.py]
 2. . .
 3
 4def get_db_connection():
 5    conn = sqlite3.connect('database.db')
 6    conn.row_factory = sqlite3.Row
 7    return conn
 8
 9def get_post(post_id):
10    conn = get_db_connection()
11    post = conn.execute('SELECT * FROM posts WHERE id = ?',
12                        (post_id,)).fetchone()
13    conn.close()
14    if post is None:
15        abort(404)
16    return post
17
18. . .

这个新函数有一个post_id参数,决定要返回哪个博客帖子。

在函数中,您使用get_db_connection()函数打开数据库连接并执行 SQL 查询以获取与给定的post_id值相关联的博客帖子。您添加了fetchone()方法以获取结果并将其存储在post变量中,然后关闭了连接。 如果post变量具有None值,这意味着数据库中没有发现结果,您使用您之前导入的abort()函数以使用404错误代码响应,并且该函数将完成执行。

接下来,在app.py文件的末尾添加以下视图函数:

1[label flask_blog/app.py]
2. . .
3
4@app.route('/<int:post_id>')
5def post(post_id):
6    post = get_post(post_id)
7    return render_template('post.html', post=post)

在这个新视图函数中,您添加了 variable rule <int:post_id> 来指定下落后的部分(/)是一个正整数(标记为 int 转换器),您需要在视图函数中访问。

保存app.py文件并打开一个新的post.html模板文件进行编辑:

1nano templates/post.html

在这个新的post.html文件中输入以下代码,它将类似于index.html文件,但它只会显示一个帖子,除此之外还会显示帖子的内容:

1[label flask_blog/templates/post.html]
2{% extends 'base.html' %}
3
4{% block content %}
5    <h2>{% block title %} {{ post['title'] }} {% endblock %}</h2>
6    <span class="badge badge-primary">{{ post['created'] }}</span>
7    <p>{{ post['content'] }}</p>
8{% endblock %}

您可以添加您在base.html模板中定义的标题块,以使页面标题同时反映在<h2>标题中显示的帖子标题。

保存并关闭文件。

您现在可以导航到以下URL,查看您在数据库中的两个帖子,以及告诉用户请求的博客帖子没有被找到的页面(因为迄今为止没有3ID号码的帖子):

1http://127.0.0.1:5000/1
2http://127.0.0.1:5000/2
3http://127.0.0.1:5000/3

回到索引页面,你会将每个帖子标题链接到其相应的页面。你会使用url_for()函数来做到这一点。首先,打开index.html模板进行编辑:

1nano templates/index.html

然后,将 href 属性的值从 # 更改为{{ url_for('post', post_id=post['id']) }},以便为的循环看起来如下:

1[label flask_blog/templates/index.html]
2{% for post in posts %}
3    <a href="{{ url_for('post', post_id=post['id']) }}">
4        <h2>{{ post['title'] }}</h2>
5    </a>
6    <span class="badge badge-primary">{{ post['created'] }}</span>
7    <hr>
8{% endfor %}

在这里,您将post转移到url_for()函数作为第一个参数,这是post()视图函数的名称,并且因为它接受了post_id参数,因此您会给它post['id]值。

保存并关闭文件。

索引页面上的链接现在将按预期运作。 通过此,您现在已经完成了负责显示博客帖子的应用程序部分的构建,然后您将添加创建,编辑和删除博客帖子的能力。

第7步:修改文章

现在您已经完成了在 Web 应用程序中的数据库中存在的博客帖子的显示,您需要允许应用程序的用户编写新的博客帖子,并将其添加到数据库中,编辑现有的文章,并删除不必要的博客帖子。

创建新邮件

到目前为止,你有一个应用程序,显示了数据库中的帖子,但没有办法添加新帖子,除非你直接连接到SQLite数据库并手动添加一个帖子。

打开app.py文件来编辑:

1nano app.py

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

  • 全球 request对象访问将通过HTML表格提交的入口请求数据。
  • url_for()函数生成URL。
  • flash()函数在处理请求时闪烁消息。

将导入文档添加到您的文件中如下:

1[label flask_blog/app.py]
2import sqlite3
3from flask import Flask, render_template, request, url_for, flash, redirect
4from werkzeug.exceptions import abort
5
6. . .

这个秘密密密钥用于保护会话,使Flask能够记住从一个请求到另一个请求的信息,例如从新邮件页面移动到索引页面。用户可以访问会话中存储的信息,但除非他们有秘密密密钥,否则无法更改它,因此您绝不能允许任何人访问您的秘密密密钥。

要设置 secret key,您将通过app.config对象将SECRET_KEY配置添加到您的应用程序中,然后在定义index()视图函数之前直接按照app定义添加它:

 1[label flask_blog/app.py]
 2. . .
 3app = Flask(__name__)
 4app.config['SECRET_KEY'] = 'your secret key'
 5
 6@app.route('/')
 7def index():
 8    conn = get_db_connection()
 9    posts = conn.execute('SELECT * FROM posts').fetchall()
10    conn.close()
11    return render_template('index.html', posts=posts)
12
13. . .

请记住,秘密密钥应该是一个长的随机字符串。

设置秘密密密钥后,您将创建一个视图函数,该函数将显示一个表单,您可以填写以创建一个新的博客帖子。

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

这会创建一个接受 GET 和 POST 请求的 /create' 路径. 默认情况下,GET 请求被接受. 为了也接受 POST 请求,这些请求由浏览器在提交表单时发送,你会将接受类型的请求的 [tuple](https://andsky.com/tech/tutorials/understanding-tuples-in-python-3)传递给 @app.route()装饰器的methods` 参数。

保存并关闭文件。

要创建模板,请在您的模板文件夹中打开名为create.html的文件:

1nano templates/create.html

将以下代码添加到新文件中:

 1[label flask_blog/templates/create.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5<h1>{% block title %} Create a New Post {% endblock %}</h1>
 6
 7<form method="post">
 8    <div class="form-group">
 9        <label for="title">Title</label>
10        <input type="text" name="title"
11               placeholder="Post title" class="form-control"
12               value="{{ request.form['title'] }}"></input>
13    </div>
14
15    <div class="form-group">
16        <label for="content">Content</label>
17        <textarea name="content" placeholder="Post content"
18                  class="form-control">{{ request.form['content'] }}</textarea>
19    </div>
20    <div class="form-group">
21        <button type="submit" class="btn btn-primary">Submit</button>
22    </div>
23</form>
24{% endblock %}

这个代码的大部分是标准的HTML,它会显示帖子标题的输入框,帖子内容的文本区域,以及提交表单的按钮。

帖子标题输入的值是 {{ request.form['title'] }},文本区域有 `{{ request.form['content'] }}'的值,这样做是这样,如果你输入的数据如果有什么不对劲,就不会丢失。例如,如果你写了一篇长篇文章而忘记给它一个标题,会显示一个信息告诉你标题是必要的。

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

1http://127.0.0.1:5000/create

您将看到一个 创建新帖子页面,其中有一个标题和内容的框。

Create a New Post Page

此表单将 POST 请求提交到创建()视图函数中,但该函数中尚无处理 POST 请求的代码,因此在填写和提交表单后不会发生任何情况。

当表单提交时,您将处理传入的 POST 请求,您将在创建()视图中执行此操作,您可以单独处理 POST 请求,通过检查请求.方法的值。

打开app.py文件来编辑:

1nano app.py

更改创建()视图函数以显示如下:

 1[label flask_blog/app.py]
 2. . .
 3
 4@app.route('/create', methods=('GET', 'POST'))
 5def create():
 6    if request.method == 'POST':
 7        title = request.form['title']
 8        content = request.form['content']
 9
10        if not title:
11            flash('Title is required!')
12        else:
13            conn = get_db_connection()
14            conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
15                         (title, content))
16            conn.commit()
17            conn.close()
18            return redirect(url_for('index'))
19
20    return render_template('create.html')

如果声明中,您可以确保仅当请求是 POST 请求时,通过比较 `request.method == 'POST' 执行随后的代码。

然后,您将提交的标题和内容从request.form对象中提取,该对象允许您访问请求中的表单数据。如果没有提供标题,则将满足如果不是标题的条件,向用户显示信息,通知他们需要标题。

然后,您将对数据库进行更改,并关闭连接. 在将博客文章添加到数据库后,您将客户端重定向到索引页面,使用重定向()函数,将由url_for()函数生成的 URL 传递给该客户端,以值``索引`作为参数。

保存并关闭文件。

现在,使用您的网页浏览器导航到创建路径:

1http://127.0.0.1:5000/create

填写表格以您选择的标题和一些内容. 一旦您提交表单,您将看到新的帖子列在索引页面上。

最后,你会显示闪烁的消息,并在base.html模板中添加导航栏的链接,以便轻松访问这个新页面。

1nano templates/base.html

通过在

Published At
Categories with 技术
comments powered by Disqus