如何使用 Flask Blueprints 和 Flask-SQLAlchemy 构建大型 Flask 应用程序

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

介绍

Flask是一个轻量级的Python网络框架,具有用于在Python中创建Web应用程序的有用的工具和功能。 SQLAlchemy是一个SQL工具包,为关系数据库提供高效和高性能的数据库访问。它提供了与诸如SQLite、MySQL和PostgreSQL等多个数据库引擎进行交互的方式,通过提供访问数据库的SQL功能。这个工具包还为您提供了一个对象关系地图(ORM),允许您使用简单的Python对象和方法进行查询和处理数据。 Flask-SQL Alchemy是一个Flask扩展,使使用SQLAlchemy与Flask更容易,提供工具和方法来与您的Flask应用程序中的数据库进行

Flask 提供了一种方法,可以用一个 Python 文件快速构建一个小型 Web 应用程序. 但是,一个小型应用程序可以成长为一个具有多个数据库表,数百条路径和复杂功能的大型应用程序的代码。

例如,在社交媒体应用程序中,你可能会在名为routes.py的文件中收集用户的路线,然后在你的大社交媒体应用程序中收集用户的数据库模型,然后在一个模型目录中收集用户的数据库模型。然后你可以对帖子,追随者,哈希标签,问题,答案,广告,市场,付款和其他功能做同样的事情。如果你想在付款代码中编辑一些业务逻辑,你可以在位于mysocialapp/models/payment.py的文件中更改付款的数据库代码,然后在位于mysocialapp/payments/routes.py的文件中更改业务逻辑。应用程序的每个部分都将有代码分离在不同的文件和目录中,有效地将

Flask 提供了一个名为 blueprints的功能来创建应用程序组件. 在上一个示例中,您可以使用蓝图来构建您的大型社交媒体应用程序,使用不同的蓝图,例如用户蓝图,帖子蓝图,追随者蓝图,每个功能。

在本教程中,您将使用Flask蓝图来构建一个Web应用程序,其中包括三个组件:包含主页和其他主要路径的主要蓝图,用于管理博客文章的帖子蓝图,以及问题和答案的蓝图。

前提条件

在本教程中,我们将把我们的项目目录称为flask_appHow to Use Templates in a Flask-Alchemy Application(LINK1)。如果您不熟悉Flask,请参阅How to Build a Website with HTML(LINK3),以及How to Use Templates in a Flask Application(LINK2) How to Use Templates in a Flask Application(LINK2)。 等基本的Flask概念,如路线、视图函数和模板的理解。您可以查看我们的How to Build a Website with HTML(LINK3)系列教程,以获得背景知识。

目标应用结构

在教程结束时,您将建立一个具有以下结构的Flask应用程序:

 1.
 2└── flask_app
 3    ├── app
 4    │   ├── extensions.py
 5    │   ├── __init__.py
 6    │   ├── main
 7    │   │   ├── __init__.py
 8    │   │   └── routes.py
 9    │   ├── models
10    │   │   ├── post.py
11    │   │   └── question.py
12    │   ├── posts
13    │   │   ├── __init__.py
14    │   │   └── routes.py
15    │   ├── questions
16    │   │   ├── __init__.py
17    │   │   └── routes.py
18    │   └── templates
19    │       ├── base.html
20    │       ├── index.html
21    │       ├── posts
22    │       │   ├── categories.html
23    │       │   └── index.html
24    │       └── questions
25    │           └── index.html
26    ├── app.db
27    └── config.py

在您的flask_app目录中,您将有一个app.db数据库文件和您的Flask应用程序的config.py配置文件. 主要的Flask应用程序将在app目录中,该目录将有一个__init__.py特殊文件,使其成为导入的包,以便正常工作,并将包含创建Flask应用程序实例的功能。

app目录将包含一个extensions.py文件来管理您将在应用程序中使用的Flask扩展(在本教程中,Flask-SQLAlchemy是使用Flask扩展的例子)。

  • main:主要路线的主要蓝图,如主页。
  • 帖子:管理博客文章的帖子蓝图。
  • 问题:管理问题和答案的问题蓝图。
  • 模型:包含Flask-SQLAlchemy模型的目录。
  • 模板:包含主要蓝图文件和每个蓝图的目录的模板目录。

步骤 1 — 安装 Flask 和 Flask-SQLAlchemy

在此步骤中,您将为您的应用程序安装所需的包。

在您的flask_app目录中,启用您的虚拟环境:

1source my_env/bin/activate

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

1pip install Flask Flask-SQLAlchemy

安装完成后,输出将打印一个类似于以下的行:

1[secondary_label Output]
2Successfully installed Flask-2.1.2 Flask-SQLAlchemy-2.5.1 Jinja2-3.1.2 MarkupSafe-2.1.1 SQLAlchemy-1.4.39 Werkzeug-2.1.2 click-8.1.3 greenlet-1.1.2 itsdangerous-2.1.2

安装所需的 Python 包后,您将在下一步设置配置文件来管理您的 Flask 应用程序的设置。

步骤 2 – 创建配置文件

在此步骤中,您将为您的 Flask 应用程序创建一个配置文件,将您的应用程序设置与其他应用程序分开,并使更改设置更容易。

在您的flask_app目录中,打开一个名为config.py的新文件,该文件将保留您的 Flask 应用程序的配置:

1nano config.py

添加以下代码:

 1[label flask_app/config.py]
 2import os
 3
 4basedir = os.path.abspath(os.path.dirname(__file__))
 5
 6class Config:
 7    SECRET_KEY = os.environ.get('SECRET_KEY')
 8    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')\
 9        or 'sqlite:///' + os.path.join(basedir, 'app.db')
10    SQLALCHEMY_TRACK_MODIFICATIONS = False

保存并关闭文件。

您将导入os模块来访问您的文件系统. 您将使用os来建立os.path.abspath(os.path.dirname(__file__))的基本目录,以正确设置数据库文件的路径。

您使用一个名为Config的类,并使用类变量设置配置值。

  • SECRET-KEY':弗拉斯克用作_机密密钥的长随机字符串,或用于从一个请求到另一个请求中记录信息的会话的密钥。 用户可以访问存储在会话中的信息,但不能修改,除非他们有密钥,所以你绝不能允许任何人访问您的秘密密钥. 详情见[关于届会的弗拉克文件] (https://flask.palletsprojects.com/en/2.2.x/api/#sessions)。 其他"弗拉斯克"扩展经常使用这个秘密密钥来保护数据. 欲了解如何创建安全密钥的更多信息,请参看[Flask应用程序中如何使用Web表单的第3步 (https://andsky.com/tech/tutorials/how-to-use-web-forms-in-a-flask-application#step-3-handling-form-requests). 当开发你的 Flask 应用程序,您应该设置一个名为 SECRET_KEY 的环境变量的密钥。 要在此 config.py 文件中获取其值并将其保存在一个名为 SECRET_KEY 的类变量中,您可以通过使用其get()方法的os.environ(https://docs.python.org/3/library/os.html#os.environ)对象获取环境变量值。 (尽管您不需要设置密钥来遵循此教程, 但您可以在此列表的末尾查看注释, 以了解如何设置密钥 。) *'SQALCHEMY-DATABASE-URI': 数据库 URI 指定了您想要建立使用 SQLAlchemy 连接的数据库 。 在这种情况下,要么从DATABASE_URI环境变量中获取,要么设定默认值。 这里的默认URI值沿用了'sqlite://path/to/app.db'格式. 您使用 s. path.join () 函数将您构建和存储在 basidir 变量和 app. db 文件名中的基础目录合并 。 在此情况下, 不设置 DATABASE_ URI 环境变量而创建 Flask 应用程序将默认连接到您的 flask_ app 目录中的 app. db` 数据库文件 。 创建数据库表格时将创建文件。 如果您想为不同的 SQL 引擎设置数据库 URI,请参见 [Flask-SQLAlchemy 如何使用 Flask-SQLAlchemy 与数据库在 Flask 应用程序中的交互 (https://andsky.com/tech/tutorials/how-to-use-flask-sqlalchemy-to-interact-with-databases-in-a-flask-application#step-2-setting-up-the-database-and-model).
  • `SQALCHEMY-TRACK-MDIDS ' : 允许或禁止跟踪对象修改的配置 。 你设定它为 " 假 " 来禁用跟踪和使用较少的内存。 更多信息,可在Flask-SQLAlchemy文档中读取[配置页] (https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/). (英语)

<$>[注] **注:**您不会在本教程中设置秘密密钥,因为您不会使用需要秘密密钥的功能。

1export SECRET_KEY="your secret key"

同样,您可以这样设置数据库URI(在 Windows 上使用设置):

1export DATABASE_URI="postgresql://username:password@host:port/database_name"

美元

接下来,您将设置一个Flask应用程序实例,并创建一些代表Flask应用程序的不同组件的蓝图。

步骤3 - 创建一个Flask应用工厂

在此步骤中,您将创建一个 Flask application factory,这是一个建立 Flask 应用实例的 Python 函数。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

1.
2├── flask_app
3   └── config.py

您的应用程序的核心代码将生活在一个项目目录中,这将是一个Python包,在本教程中,我们将称之为app,但您可以使用项目的名称或其他常见目录名称,如src,core或类似的东西。

您将使包含应用程序核心代码的文件夹成为Python包,以便导入在整个代码库中正确工作,并增加其可维护性。

要将应用程序项目目录变成一个Python包,你将创建一个特殊的__init__.py文件,它将目录标记为Python包。这个__init__.py文件将保留你的Flask工厂函数的代码,这是你将使用的函数来设置和创建Flask应用程序实例,在那里你将所有的Flask蓝图连接在一起。想想工厂函数是你所有的Flask组件(蓝图)合并到一个应用程序的中心函数,你可以使用它来创建不同的Flask应用程序实例,用不同的配置。

在你的flask_app目录中,创建这个新的app目录:

1mkdir app

然后在app目录中打开一个新的__init__.py文件:

1nano app/__init__.py

添加以下代码:

 1[label flask_app/app/__init__.py]
 2from flask import Flask
 3
 4from config import Config
 5
 6def create_app(config_class=Config):
 7    app = Flask(__name__)
 8    app.config.from_object(config_class)
 9
10    # Initialize Flask extensions here
11
12    # Register blueprints here
13
14    @app.route('/test/')
15    def test_page():
16        return '<h1>Testing the Flask Application Factory Pattern</h1>'
17
18    return app

保存并关闭文件。

在此文件中,您从flask包中导入Flask类,然后从上一步中在flask_app目录中创建的config.py文件中导入Config配置类。

create_app()函数是 Flask application factory function。它使用熟悉的app = Flask(__name__)行来创建一个名为app的应用程序实例,通过app.config.from_object()方法导入对象的配置值来配置应用程序,将config_class参数的值传递给它,该参数将Config类作为默认值。一旦您创建它们,您将对# Initialize Flask extensions评论下的Flask扩展进行初始化,并在# Register blueprints评论下注册您的应用程序蓝图。

您使用工厂函数中的app.route()装饰器创建测试路线,以展示如何在应用程序工厂内注册路线。

最后,create_app()工厂函数返回您用return app字段构建的应用程序实例。

Flask 会自动检测到您的应用程序包中的create_app()工厂函数,并使用它创建应用程序实例,但您需要先设置在开发模式下运行 Flask 应用程序所需的环境变量。

在您的flask_app目录中,您的虚拟环境已启用,您将通过将核心应用程序目录名称app作为值传递给FLASK_APP环境变量来告诉Flask,然后将FLASK_ENV环境变量设置为development,以便在开发模式下运行应用程序,并获得调试器的访问。

首先,将app包设置为Flask应该搜索create_app()工厂函数的位置:

1export FLASK_APP=app

你可以用来构建你的Flask应用程序在一个单一的Python文件中,称为app.py。在这种情况下,你也可以使用相同的命令告诉Flask在哪里找到你的应用程序。

设置FLASK_ENV环境变量以在开发模式下运行应用程序:

1export FLASK_ENV=development

然后运行应用程序:

1flask run

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

1http://127.0.0.1:5000/test/

该网站将载有测试Flask应用程序工厂模式标题。

您现在已经创建了一个Flask应用程序工厂函数,接下来,您将创建Flask蓝图,并在这个工厂函数中注册它们。

步骤 4 – 创建Flask蓝图

在此步骤中,您将为主路径创建蓝图,以管理您的Flask应用程序的主要组件,然后在您的工厂功能上注册蓝图。您将为博客帖子,问题和答案创建另一个蓝图。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

1.
2├── flask_app
3    ├── app
4    │   └── __init__.py
5    └── config.py

创建主蓝图并渲染其模板

您现在将创建应用程序的主要蓝图并渲染其模板。

离开在上一个步骤中启动的开发服务器,然后打开一个新的终端。

在新终端中导航到您的flask_app目录,然后在app目录中创建一个名为main的主要蓝图目录:

1mkdir app/main

接下来,在新的主要目录中打开一个新的__init__.py主文件:

1nano app/main/__init__.py

这是你将创建你的主要蓝图的地方. 添加以下代码到这个文件:

1[label flask_app/app/main/__init__.py]
2from flask import Blueprint
3
4bp = Blueprint('main', __name__)

保存并关闭文件。

在这里,你从flask包中导入了 Blueprint类,然后使用这个类来创建一个蓝图对象 bp,传递给它两个参数:一个名称 (在这种情况下, 'main') 和一个特殊的变量 name`,其中包含当前 Python 模块的名称。

您现在有一个蓝图对象,后者将有路径和函数,您可以将其插入到您使用您在上一步中写的create_app()工厂函数创建的Flask应用程序中。

接下来,您将在您的主要蓝图目录中创建一个routes.py文件,其中将包含主要蓝图的路径。

1nano app/main/routes.py

您将使用bp对象创建路线,在新文件中添加以下路线:

1[label flask_app/app/main/routes.py]
2from app.main import bp
3
4@bp.route('/')
5def index():
6    return 'This is The Main Blueprint'

保存并关闭文件。

在这里,您从主蓝图中导入bp蓝图对象,您可以通过app.main访问。在导入行中,app是项目的包,main是主蓝图包,而bp是您在主蓝图的__init__.py文件中声明的对象。

您使用bp对象创建一条/路线和一个index()视图函数,使用bp.route()装饰器,类似于熟悉的app.route()装饰器。

要让 Flask 使用这些路径并使它们直接从蓝图中导入,您需要将这个 routes.py 文件导入蓝图的 __init__.py 文件中。

1nano app/main/__init__.py

添加文件末尾的突出导入行:

1[label flask_app/app/main/__init__.py]
2from flask import Blueprint
3
4bp = Blueprint('main', __name__)
5
6from app.main import routes

保存并关闭文件。

随着这个补充,注册蓝图也会记录其路线。

现在你已经创建了蓝图并添加了路线,你需要告诉Flask这个新的蓝图,以便它可以被视为Flask应用程序的一部分。

打开app/__init__.py文件来编辑你的工厂函数:

1nano app/__init__.py

编辑create_app()工厂函数以匹配下列块,添加突出的行:

 1[label flask_app/app/main/__init__.py]
 2...
 3def create_app(config_class=Config):
 4    app = Flask(__name__)
 5    app.config.from_object(config_class)
 6
 7    # Initialize Flask extensions here
 8
 9    # Register blueprints here
10    from app.main import bp as main_bp
11    app.register_blueprint(main_bp)
12
13    @app.route('/test/')
14    def test_page():
15        return '<h1>Testing the Flask Application Factory Pattern</h1>'
16
17    return app

保存并关闭文件。

您从主蓝图中导入bp蓝图对象,并将其改名为main_bp以便可读性,然后使用app.register_blueprint()方法将该主蓝图注册为 Flask 作为应用程序的一部分。

随着开发服务器运行,导航到以下URL:

1http://127.0.0.1:5000/

该页面将加载文本 这是主要蓝图,这是您在主要路径中返回的文本。

接下来,您将在主蓝图中编辑主路线,以渲染 HTML 模板,该模板将在使用 Flask 蓝图时展示如何渲染模板。

打开主蓝图的 routes.py 文件进行修改:

1nano app/main/routes.py

用突出的行编辑文件:

1[label flask_app/app/main/routes.py]
2from flask import render_template
3from app.main import bp
4
5@bp.route('/')
6def index():
7    return render_template('index.html')

保存并关闭文件。

在这里,您导入render_template()函数,并在路径中使用它来渲染名为index.html的模板文件。

您现在必须创建一个模板目录和基础模板,所有其他模板都将共享,以避免代码重复。

在你的app目录中创建一个模板目录:

1mkdir app/templates

打开一个名为base.html的新文件,作为基础模板:

1nano app/templates/base.html

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

 1[label flask_app/app/templates/base.html]
 2<!DOCTYPE html>
 3<html lang="en">
 4<head>
 5    <meta charset="UTF-8">
 6    <title>{% block title %} {% endblock %} - FlaskApp</title>
 7    <style>
 8        h2 {
 9            width: 100%;
10        }
11
12        .title {
13            margin: 5px;
14            width: 100%;
15        }
16
17        .content {
18            margin: 5px;
19            width: 100%;
20            display: flex;
21            flex-direction: row;
22            flex-wrap: wrap;
23        }
24
25        .post {
26            flex: 20%;
27            padding: 10px;
28            margin: 5px;
29            background-color: #f3f3f3;
30            inline-size: 100%;
31        }
32
33        .title a {
34            color: #00a36f;
35            text-decoration: none;
36        }
37
38        nav a {
39            color: #d64161;
40            font-size: 3em;
41            margin-left: 50px;
42            text-decoration: none;
43        }
44
45    </style>
46</head>
47<body>
48    <nav>
49        <a href="{{ url_for('main.index') }}">FlaskApp</a>
50        <a href="#">Posts</a>
51        <a href="#">Categories</a>
52        <a href="#">Questions</a>
53    </nav>
54    <hr>
55    <div class="content">
56        {% block content %} {% endblock %}
57    </div>
58</body>
59</html>

保存并关闭文件。

此基础模板具有 HTML 锅炉板,您将在其他模板中重复使用。

基础模板有标题块、一些CSS、导航栏以链接到应用程序的不同部分,以及内容块。

您使用blueprint_name.view_function_name语法链接到路线时,使用url_for()函数与蓝图。 该索引页面由主蓝图中的index()视图函数处理;因此,您将main.index传输到url_for()函数来构建链接。

现在,创建您在主蓝图的index()视图函数中渲染的index.html文件:

1nano app/templates/index.html

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

1[label flask_app/app/templates/index.html]
2{% extends 'base.html' %}
3
4{% block content %}
5    <span class="title"><h1>{% block title %} The Home Page of FlaskApp {% endblock %}</h1></span>
6    <div class="content">
7        <h2>This is the main Flask blueprint</h2>
8    </div>
9{% endblock %}

保存并关闭文件。

在这里,您扩展了基础模板. 您更换了内容块,使用一个<h1>标题,它也作为一个标题和一个<h2>标题,表示索引页面是主Flask蓝图的一部分。

当开发服务器运行时,请使用您的浏览器访问索引页面,或者如果已经打开,请更新它:

1http://127.0.0.1:5000/

一个类似下面的图像的页面将加载:

Main Blueprint

您现在已经设置了蓝图,将路线添加到其routes.py文件中,在应用程序中注册了它,并为其渲染了模板。

创建邮件蓝图并渲染其模板

现在你将创建博客帖子的蓝图,注册它,并渲染其模板。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

 1.
 2├── flask_app
 3    ├── app
 4    │   ├── __init__.py
 5    │   ├── main
 6    │   │   ├── __init__.py
 7    │   │   └── routes.py
 8    │   └── templates
 9    │       ├── base.html
10    │       └── index.html
11    └── config.py

要创建博客帖子的新蓝图,您将按照上一节中的相同步骤进行。

首先,创建一个新的帖子目录,以保持蓝图的文件:

1mkdir app/posts

接下来,在新的帖子目录中打开一个新的__init__.py文件:

1nano app/posts/__init__.py

创建一个bp蓝图对象,并将您创建的路径导入蓝图的routes.py文件:

1[label flask_app/app/posts/__init__.py]
2from flask import Blueprint
3
4bp = Blueprint('posts', __name__)
5
6from app.posts import routes

保存并关闭文件。

在之前的代码块中,你使用帖子作为蓝图的名称,你还从尚未创建的routes.py文件中导入路线。

接下来,打开新的 routes.py 文件,在那里您将放置帖子的路线蓝图:

1nano app/posts/routes.py

将以下路径添加到此文件中:

 1[label flask_app/app/posts/routes.py]
 2from flask import render_template
 3from app.posts import bp
 4
 5@bp.route('/')
 6def index():
 7    return render_template('posts/index.html')
 8
 9@bp.route('/categories/')
10def categories():
11    return render_template('posts/categories.html')

保存并关闭文件。

在这里,你有两个路径:应用程序的帖子组件的索引页面的路径和类别的路径,这将是帖子组件的一部分。

索引路径中,您将带有posts/index.html路径的模板文件渲染,这意味着Flask将在模板目录中搜索名为posts的目录,然后在posts目录中搜索index.html文件。

类别路径中,您将渲染一个categories.html模板,该模板也将位于模板文件夹内的帖子目录中。

现在,在您的模板目录中创建新的帖子目录:

1mkdir app/templates/posts

接下来,在帖子目录中创建新的index.html文件,这是你在index()视图函数中渲染的帖子蓝图中的文件:

1nano app/templates/posts/index.html

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

1[label flask_app/app/templates/posts/index.html]
2{% extends 'base.html' %}
3
4{% block content %}
5    <span class="title"><h1>{% block title %} The Posts Page {% endblock %}</h1></span>
6    <div class="content">
7        <h2>This is the posts Flask blueprint</h2>
8    </div>
9{% endblock %}

保存并关闭文件。

您还将一个<h1>标题设置为标题和一个<h2>标题来标记页面作为帖子蓝图的一部分。

接下来,在帖子目录中创建一个新的categories.html文件,这是你在categories()帖子蓝图视图功能中渲染的文件:

1nano app/templates/posts/categories.html

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

1[label flask_app/app/templates/posts/categories.html]
2{% extends 'base.html' %}
3
4{% block content %}
5    <span class="title"><h1>{% block title %} Categories {% endblock %}</h1></span>
6    <div class="content">
7        <h2>This is the categories page within the posts blueprint</h2>
8    </div>
9{% endblock %}

保存并关闭文件。

您将基础模板扩展,并将<h1>标题设置为标题和<h2>标题,以将页面标记为帖子蓝图的一部分。

您已经创建了帖子的蓝图,添加了路线,并创建了渲染的模板. 您现在将将此蓝图注册到您的工厂函数,以便Flask将其识别为应用程序的一部分。

打开app/__init__.py文件来编辑你的工厂函数:

1nano app/__init__.py

通过添加突出的行来编辑create_app()工厂函数:

 1[label flask_app/app/__init__.py]
 2
 3def create_app(config_class=Config):
 4    app = Flask(__name__)
 5    app.config.from_object(config_class)
 6
 7    # Initialize Flask extensions here
 8
 9    # Register blueprints here
10    from app.main import bp as main_bp
11    app.register_blueprint(main_bp)
12
13    from app.posts import bp as posts_bp
14    app.register_blueprint(posts_bp, url_prefix='/posts')
15
16    @app.route('/test/')
17    def test_page():
18        return '<h1>Testing the Flask Application Factory Pattern</h1>'
19
20    return app

保存并关闭文件。

在这里,您从帖子蓝图包中导入了bp蓝图对象,并为可读性更名为posts_bp

您使用app.register_blueprint()方法登记帖子蓝图,将其传递为posts_bp蓝图对象. 您还将为url_prefix参数传递一个值的posts/posts值,该参数将为蓝图的路线先定为此字符串。

随着新帖子蓝图注册和开发服务器运行,使用您的浏览器导航到以下URL:

1http://127.0.0.1:5000/posts/
2http://127.0.0.1:5000/posts/categories/

该标题将加载为 http://127.0.0.1:5000/posts/ 页面. 一个标题将加载为 http://127.0.0.1:5000/posts/categories/ 页面。

要使导航栏中的 ** 帖子** 和 ** 类别** 链接可用,请打开基板模板以进行修改:

1nano app/templates/base.html

用突出表达式更改<nav>标签:

1[label flask_app/app/templates/base.html]
2    <nav>
3        <a href="{{ url_for('main.index') }}">FlaskApp</a>
4        <a href="{{ url_for('posts.index') }}">Posts</a>
5        <a href="{{ url_for('posts.categories') }}">Categories</a>
6        <a href="#">Questions</a>
7    </nav>

保存并关闭文件。

您将链接到帖子索引的url_for('posts.index')函数调用和类别页面的url_for('posts.categories')

更新应用程序中的任何页面以启用 帖子分类链接功能。

您现在在您的应用程序中注册了帖子蓝图,接下来,您将添加问题和答案蓝图。

创建问题蓝图并渲染其模板

现在你将创建问题蓝图,注册它,并渲染其模板。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

 1.
 2├── flask_app
 3    ├── app
 4    │   ├── __init__.py
 5    │   ├── main
 6    │   │   ├── __init__.py
 7    │   │   └── routes.py
 8    │   ├── posts
 9    │   │   ├── __init__.py
10    │   │   └── routes.py
11    │   └── templates
12    │       ├── base.html
13    │       ├── index.html
14    │       └── posts
15    │           ├── categories.html
16    │           └── index.html
17    └── config.py

要创建一个新的问题和答案蓝图,创建一个新的问题目录,以存储蓝图的文件:

1mkdir app/questions

接下来,在新的问题目录中打开一个新的__init__.py文件:

1nano app/questions/__init__.py

创建一个bp蓝图对象,并导入您将在蓝图的routes.py文件中创建的路径:

1[label flask_app/app/questions/__init__.py]
2from flask import Blueprint
3
4bp = Blueprint('questions', __name__)
5
6from app.questions import routes

保存并关闭文件。

在之前的代码块中,你使用问题作为蓝图的名称,你还从你尚未创建的routes.py文件中导入路线。

接下来,打开新的 routes.py 文件,在那里您将放置问题蓝图的路径:

1nano app/questions/routes.py

将以下路径添加到此文件中:

1[label flask_app/app/questions/routes.py]
2from flask import render_template
3from app.questions import bp
4
5@bp.route('/')
6def index():
7    return render_template('questions/index.html')

保存并关闭文件。

您使用问题蓝图对象创建一个/路线,在名为问题的目录中渲染一个名为index.html的模板文件,您将在模板文件夹中创建。

在模板目录中创建问题目录,然后打开其中一个index.html文件:

1mkdir app/templates/questions
2nano app/templates/questions/index.html

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

 1[label flask_app/app/templates/questions/index.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <span class="title">
 6        <h1>{% block title %} Questions {% endblock %}</h1>
 7    </span>
 8    <div class="questions">
 9        <h2>Questions Blueprint</h2>
10    </div>
11{% endblock %}

保存并关闭文件。

在这里,您设置了一个标题和子标题,类似于其他蓝图中的以前的索引模板。

现在打开app/__init__.py,在create_app()工厂函数中注册问题蓝图:

1nano app/__init__.py

通过添加突出的行来编辑create_app()工厂函数:

 1[label flask_app/app/__init__.py]
 2
 3def create_app(config_class=Config):
 4    app = Flask(__name__)
 5    app.config.from_object(config_class)
 6
 7    # Initialize Flask extensions here
 8
 9    # Register blueprints here
10    from app.main import bp as main_bp
11    app.register_blueprint(main_bp)
12
13    from app.posts import bp as posts_bp
14    app.register_blueprint(posts_bp, url_prefix='/posts')
15
16    from app.questions import bp as questions_bp
17    app.register_blueprint(questions_bp, url_prefix='/questions')
18
19    @app.route('/test/')
20    def test_page():
21        return '<h1>Testing the Flask Application Factory Pattern</h1>'
22
23    return app

保存并关闭文件。

您将问题蓝图注册,就像您在帖子蓝图中一样,将‘/questions’前缀添加到其路径中。

当您的开发服务器运行时,使用您的浏览器导航到以下URL:

1http://127.0.0.1:5000/questions/

** 问题和 ** 问题蓝图的标题将显示在页面上。

您现在将使 ** 问题 ** 链接功能。 打开基础模板以编辑导航栏:

1nano app/templates/base.html

用突出表达式更改 <nav> 标签:

1[label flask_app/app/templates/base.html]
2    <nav>
3        <a href="{{ url_for('main.index') }}">FlaskApp</a>
4        <a href="{{ url_for('posts.index') }}">Posts</a>
5        <a href="{{ url_for('posts.categories') }}">Categories</a>
6        <a href="{{ url_for('questions.index') }}">Questions</a>
7    </nav>

保存并关闭文件。

在这里,您可以使用url_for('questions.index')函数调用链接到问题索引页面。

更新应用程序中的任何页面以启用导航栏中的 ** 问题 ** 链接功能。

你已经创建了几种蓝图来管理应用程序的不同组件. 你在你的工厂函数上注册了蓝图,并为每个路线渲染了模板。接下来,你将Flask-SQLAlchemy添加到应用程序中,以便在Flask应用程序中管理和组织大型数据库。

步骤 5 — 将 Flask-SQLAlchemy 模型添加到您的 Flask 应用程序

在此步骤中,您将 Flask-SQLAlchemy 与您的应用程序集成,为数据库模型添加目录,并为帖子创建模型,为问题创建模型。您将插入几个博客帖子到帖子表中,然后编辑帖子索引路线,以显示数据库中的所有帖子。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

 1.
 2├── flask_app
 3    ├── app
 4    │   ├── __init__.py
 5    │   ├── main
 6    │   │   ├── __init__.py
 7    │   │   └── routes.py
 8    │   ├── posts
 9    │   │   ├── __init__.py
10    │   │   └── routes.py
11    │   ├── questions
12    │   │   ├── __init__.py
13    │   │   └── routes.py
14    │   └── templates
15    │       ├── base.html
16    │       ├── index.html
17    │       ├── posts
18    │       │   ├── categories.html
19    │       │   └── index.html
20    │       └── questions
21    │           └── index.html
22    └── config.py

创建用于管理 Flask 扩展和集成 Flask-SQLAlchemy 的文件

要将Flask-SQLAlchemy扩展添加到您的应用程序中,您首先将添加一个名为extensions.py的Python模块,在其中您将设置您的各种Flask扩展到您的app目录中。

在你的应用程序目录中打开一个新的extensions.py文件:

1nano app/extensions.py

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

1[label flask_app/app/extensions.py]
2from flask_sqlalchemy import SQLAlchemy
3db = SQLAlchemy()

保存并关闭文件。

在这里,您从 Flask-SQLAlchemy 包中导入SQLAlchemy()类,然后使用它创建一个没有参数的db数据库对象。

您将使用此db对象将 SQLAlchemy 集成到您在工厂函数中构建的 Flask 应用程序中。

1nano app/__init__.py

编辑文件以导入和初始化数据库对象:

 1[label flask_app/app/__init__.py]
 2from flask import Flask
 3
 4from config import Config
 5from app.extensions import db
 6
 7def create_app(config_class=Config):
 8    app = Flask(__name__)
 9    app.config.from_object(config_class)
10
11    # Initialize Flask extensions here
12    db.init_app(app)
13
14    # Register blueprints here
15    from app.main import bp as main_bp
16    app.register_blueprint(main_bp)
17
18    from app.posts import bp as posts_bp
19    app.register_blueprint(posts_bp, url_prefix='/posts')
20
21    from app.questions import bp as questions_bp
22    app.register_blueprint(questions_bp, url_prefix='/questions')
23
24    @app.route('/test/')
25    def test_page():
26        return '<h1>Testing the Flask Application Factory Pattern</h1>'
27
28    return app

在这里,您从您之前创建的app.extensions模块中导入db数据库对象。在注册蓝图之前,您可以使用db.init_app()方法将数据库对象连接到app应用程序实例。

请记住,你已经配置了 Flask-SQLAlchemy 使用在你的 flask_app 目录中的 'config.py' 文件中的 'Config' 对象。

1nano config.py
 1[label flask_app/config.py]
 2import os
 3
 4basedir = os.path.abspath(os.path.dirname(__file__))
 5
 6class Config:
 7    SECRET_KEY = os.environ.get('SECRET_KEY')
 8    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')\
 9        or 'sqlite:///' + os.path.join(basedir, 'app.db')
10    SQLALCHEMY_TRACK_MODIFICATIONS = False

如果您没有设置DATABASE_URI环境变量,则db对象默认情况下将连接到名为app.db的SQLite文件,该文件将在您创建数据库表后出现在您的flask_app目录中。

您可以使用 Flask shell 检查数据库是否正确注册,首先,随着虚拟环境的启用,请确保您在您的 flask_app 目录中设置了 Flask 环境变量:

1export FLASK_APP=app
2export FLASK_ENV=development

打开瓶子壳:

1flask shell

app.extensions模块中导入db对象,然后打印:

1from app.extensions import db
2print(db)

您将收到数据库的路径,类似于以下:

1[secondary_label Output]
2<SQLAlchemy engine=sqlite:///your_path_to_flask_app/app.db>

此输出意味着 db 对象已正确注册. 如果您在 Flask 壳中收到运行代码的错误,请确保您在迁移到下一节之前在工厂函数中正确注册了 db 对象。

创建和与邮件模型互动

在大型应用程序中,您可能有数百个数据库表,这意味着您需要编写数百个 SQLAlchemy 模型来管理它们。将所有模型放在一个文件中会使您的应用程序难以维护,因此您将模型分成单独的 Python 文件在一个模型目录中。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

 1.
 2├── flask_app
 3    ├── app
 4    │   ├── extensions.py
 5    │   ├── __init__.py
 6    │   ├── main
 7    │   │   ├── __init__.py
 8    │   │   └── routes.py
 9    │   ├── posts
10    │   │   ├── __init__.py
11    │   │   └── routes.py
12    │   ├── questions
13    │   │   ├── __init__.py
14    │   │   └── routes.py
15    │   └── templates
16    │       ├── base.html
17    │       ├── index.html
18    │       ├── posts
19    │       │   ├── categories.html
20    │       │   └── index.html
21    │       └── questions
22    │           └── index.html
23    └── config.py

要创建自己的文件中的帖子数据库模型,首先在你的应用目录中创建一个名为模型的目录:

1mkdir app/models

然后,在您的模型目录中打开一个名为post.py的新文件:

1nano app/models/post.py

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

 1[label flask_app/app/models/post.py]
 2from app.extensions import db
 3
 4class Post(db.Model):
 5    id = db.Column(db.Integer, primary_key=True)
 6    title = db.Column(db.String(150))
 7    content = db.Column(db.Text)
 8
 9    def __repr__(self):
10        return f'<Post "{self.title}">'

保存并关闭文件。

你从app.extensions模块中导入了db数据库对象,然后使用db.Model类来创建一个名为Post的Flask-SQLAlchemy数据库模型,在模型中,你有一个ID整数列作为主键(id),一个列为帖子标题(title),以及一个内容的文本列(content).你使用特殊的__repr__()方法为每个帖子对象提供一个字符串表示,使用其标题。有关Flask-SQL Alchemy的更多信息,你可以查看如何使用Flask-SQL Alchemy在Flask应用程序中与数据库进行交互(LINK0)。

接下来,打开 Flask 壳以创建基于邮件模型的邮件表:

1flask shell

运行以下代码来创建帖子表:

1from app.extensions import db
2from app.models.post import Post
3db.create_all()

你从app.extensions模块中导入db对象,然后从app.models.post模块中导入Post模型,然后使用create_all()方法创建邮件表。

如果您收到错误,请检查您的app/extensions.pyapp/models/post.py 文件,并查看之前的步骤,以确保您按照所写的方式遵循。

<$>[注] 注: db.create_all() 函数不会重新创建或更新一个表,如果它已经存在,例如,如果您想通过添加一个新的列来修改您的模型,然后运行 db.create_all() 函数,则您对模型所做的更改不会应用到表中,如果该表已经存在于数据库中。 解决方案是使用 db.drop_all() 函数删除所有现有的数据库表,然后用 `db.create_all()' 函数重新创建它们:

1db.drop_all()
2db.create_all()

这些命令将应用您对模型所做的更改,并删除数据库中的所有现有数据. 要更新数据库并保存现有数据,您需要使用 schema migration,允许您修改表并保存数据。

接下来,运行以下代码来创建十个随机帖子:

 1import random
 2
 3for i in range(0, 10):
 4    random_num = random.randrange(1, 1000)
 5    post = Post(title=f'Post #{random_num}',
 6                content=f'Content #{random_num}')
 7    db.session.add(post)
 8    print(post)
 9    print(post.content)
10    print('--')
11    db.session.commit()

您将导入db数据库对象、Post数据库模型和RandomPython模块,您将使用该模块生成随机数字以创建具有不同标题和内容的样本帖子。

for循环中,您使用random.randrange()方法(https://docs.python.org/3/library/random.html#random.randrange)生成11000之间的随机整数,并将其保存到名为random_num的变量中,然后使用Post模型创建邮件对象,并使用random_num变量中的随机数生成示例邮件标题和内容。

然后将邮件对象添加到数据库会话中,打印对象本身及其内容,并执行交易。

您将收到相似的输出,但有不同的数字:

 1[secondary_label Output]
 2<Post "Post #58">
 3Content #58
 4--
 5<Post "Post #55">
 6Content #55
 7--
 8<Post "Post #994">
 9Content #994
10--
11<Post "Post #394">
12Content #394
13--
14<Post "Post #183">
15Content #183
16--
17<Post "Post #633">
18Content #633
19--
20<Post "Post #790">
21Content #790
22--
23<Post "Post #883">
24Content #883
25--
26<Post "Post #259">
27Content #259
28--
29<Post "Post #581">
30Content #581
31--

每个帖子都有随机生成的号码,这些帖子现在将在您的数据库中。

让 Flask 壳运行,打开一个新的终端窗口. 源您的环境,并导航到您的应用程序文件夹。

现在你在表中有几个样本帖子,你可以在帖子索引页面上显示它们. 首先,打开帖子路由文件来修改索引路径:

1nano app/posts/routes.py

通过添加突出的行来编辑导入和索引路径:

 1[label flask_app/app/posts/routes.py]
 2from flask import render_template
 3from app.posts import bp
 4from app.extensions import db
 5from app.models.post import Post
 6
 7@bp.route('/')
 8def index():
 9    posts = Post.query.all()
10    return render_template('posts/index.html', posts=posts)

保存并关闭文件。

您导入db数据库对象和Post模型,然后将数据库中的所有帖子传输到帖子索引模板中。

打开帖子的索引模板进行修改,以显示您传递给它的帖子:

1nano app/templates/posts/index.html

通过添加突出的行来编辑文件:

 1[label flask_app/app/templates/posts/index.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <span class="title"><h1>{% block title %} The Posts Page {% endblock %}</h1></span>
 6    <div class="content">
 7        <h2>This is the posts Flask blueprint</h2>
 8        {% for post in posts %}
 9            <div class="post">
10                <p><b>#{{ post.id }}</b></p>
11                <p class="title">
12                    <b>
13                        <a href="#">
14                            {{ post.title }}
15                        </a>
16                    </b>
17                </p>
18                <div class="content">
19                    <p>{{ post.content }}</p>
20                </div>
21                <hr>
22            </div>
23        {% endfor %}
24    </div>
25{% endblock %}

保存并关闭文件。

在这里,您通过帖子滚动,并显示每个帖子的ID,标题和内容。

随着开发服务器运行,请访问帖子索引页面或更新它,如果打开:

1http://127.0.0.1:5000/posts/

您生成的样本帖子将显示在索引页面上,类似于下面的图像:

The Posts Page

您现在可以将功能添加到您的应用程序中,使用新的路径和模板,例如创建、编辑和删除帖子。

创建和与问题模型互动

您已经创建了一个帖子模型,并在帖子蓝图中与它交互,现在您将添加问题数据库模型来管理问题和答案。

在本教程中,您的「flask_app」目录结构如下(不包括虚拟环境目录):

 1.
 2├── flask_app
 3    ├── app
 4    │   ├── extensions.py
 5    │   ├── __init__.py
 6    │   ├── main
 7    │   │   ├── __init__.py
 8    │   │   └── routes.py
 9    │   ├── models
10    │   │   └── post.py
11    │   ├── posts
12    │   │   ├── __init__.py
13    │   │   └── routes.py
14    │   ├── questions
15    │   │   ├── __init__.py
16    │   │   └── routes.py
17    │   └── templates
18    │       ├── base.html
19    │       ├── index.html
20    │       ├── posts
21    │       │   ├── categories.html
22    │       │   └── index.html
23    │       └── questions
24    │           └── index.html
25    ├── app.db
26    └── config.py

若要创建问题数据库模型,请在模型目录中打开名为question.py的新文件:

1nano app/models/question.py

添加以下代码:

 1[label flask_app/app/models/question.py]
 2from app.extensions import db
 3
 4class Question(db.Model):
 5    id = db.Column(db.Integer, primary_key=True)
 6    content = db.Column(db.Text)
 7    answer = db.Column(db.Text)
 8
 9    def __repr__(self):
10        return f'<Question {self.content}>'

保存并关闭文件。

在这里,你从app.extensions模块中导入了db数据库对象,然后使用db.Model类创建一个名为Question的模型,在模型中,你有一个ID整数列作为主键(‘id’),一个文本列为问题内容(‘content’),以及一个文本列为答案(‘answer’)。

在运行 Flask 壳的终端会话中,运行以下代码以根据问题模型创建问题表:

1flask shell

运行以下代码创建问题表,并添加一些问题和答案:

1from app.extensions import db
2from app.models.question import Question
3db.create_all()
4
5q1 = Question(content='Why is the sky blue?', answer='Because... Why not?')
6q2 = Question(content='What is love?', answer='A portal to the underworld.')
7db.session.add_all([q1, q2])
8db.session.commit()

如果您收到错误,请检查您的app/models/question.py文件,以确保您的代码是用正确的语法写的。

您导入数据库对象和问题模型,然后使用「db.create_all()」创建表,最后将两个问题对象添加到数据库会话中,并执行交易。

离开瓶子壳:

1exit()

要做到这一点,请打开问题蓝图的routes.py文件以进行修改,以查询并显示您在您的问题表中的问题:

1nano app/questions/routes.py

通过添加突出的行来编辑文件:

1[label flask_app/app/questions/routes.py]
2from flask import render_template
3from app.questions import bp
4from app.models.question import Question
5
6@bp.route('/')
7def index():
8    questions = Question.query.all()
9    return render_template('questions/index.html', questions=questions)

保存并关闭文件。

在这里,您可以导入问题模型,在数据库中获取所有问题,然后将其传输到问题索引模板。

接下来,您将显示您转移到问题索引模板的问题,并添加一个网页表格,以允许用户添加新问题。

1nano app/templates/questions/index.html

通过添加突出的行来编辑文件:

 1[label flask_app/app/templates/questions/index.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <span class="title">
 6        <h1>{% block title %} Questions {% endblock %}</h1>
 7    </span>
 8    <div class="questions">
 9        <h2>Questions Blueprint</h2>
10
11        <div class="question">
12            <div class="new-question">
13                <form method="POST">
14                    <p>
15                        <textarea id="q-content"
16                                name="content"
17                                placeholder="Question"
18                                cols="30" rows="3"></textarea>
19                    </p>
20                    <textarea id="q-answer"
21                            name="answer"
22                            placeholder="Answer"
23                            cols="30" rows="3"></textarea>
24                    <p><input type="submit"></p>
25                </form>
26            </div>
27            <div class="questions-list">
28                {% for question in questions %}
29                    <div class="question">
30                        <h4>{{ question.content }}</h4>
31                        <p>{{ question.answer }}</p>
32                        <hr>
33                    </div>
34                {% endfor %}
35            </div>
36        </div>
37
38    </div>
39{% endblock %}

保存并关闭文件。

在这里,您创建一个表单,其中包含两个文本区域:一个用于问题内容,一个用于答案。

在表单下方,您可以通过您从问题索引路径传递的问题变量,显示每个问题的内容和答案。

随着开发服务器运行,使用您的浏览器导航到问题索引页面:

1http://127.0.0.1:5000/questions/

页面将载有蓝图标题、提交表格和两个样本问题:

Questions Index

但是,填写和提交表单会导致405 方法不允许 HTTP 错误,因为表单会向问题索引路径发送POST请求,但该路径不会接受或处理POST请求。

打开问题蓝图的routes.py文件:

1nano app/questions/routes.py

通过添加突出的行来编辑文件:

 1[label flask_app/app/questions/routes.py]
 2from flask import render_template, request, url_for, redirect
 3from app.questions import bp
 4from app.models.question import Question
 5from app.extensions import db
 6
 7@bp.route('/', methods=('GET', 'POST'))
 8def index():
 9    questions = Question.query.all()
10
11    if request.method == 'POST':
12        new_question = Question(content=request.form['content'],
13                                answer=request.form['answer'])
14        db.session.add(new_question)
15        db.session.commit()
16        return redirect(url_for('questions.index'))
17
18    return render_template('questions/index.html', questions=questions)

保存并关闭文件。

您允许GETPOST方法,通过将('GET,POST)转到methods参数中。您在if request.method ==POST:条件下处理POST请求。在其中,您使用内容创建一个新问题对象,并回答用户提交的答案,您从request.form对象中获取。

该表格现在将起作用,您可以将新问题和答案添加到您的数据库中。您可以在http://127.0.0.1:5000/questions/` URL上测试此功能。

您已将 Flask-SQLAlchemy 集成到您的应用程序中,添加了模型目录来组织您的代码。

您可以将最终文件与存储在 DigitalOcean 社区存储库中的代码进行比较。

结论

您使用蓝图构建了一个大型Flask应用程序,并将其与模板和模型进行组织,您将其设置为每个组件都有自己的路线,模板和模型。

示例 Web 应用程序现在有三个主要组件,可以以不同的方式扩展:

您还可以为身份验证、付款、管理等功能添加更多蓝图。

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

Published At
Categories with 技术
comments powered by Disqus