Skip to content

Latest commit

 

History

History
501 lines (328 loc) · 28.7 KB

File metadata and controls

501 lines (328 loc) · 28.7 KB

六、示例——构建 BugZot

在过去的几章中,我们讨论了许多用于构建企业级应用的技术。但是,如果我们不知道在哪里使用这些知识,那么这些知识又有什么好处呢?

在本章中,我们将介绍构建企业级 web 应用的过程,该应用将用于跟踪 Omega 公司销售的产品的各个利益相关者报告的错误。从现在起,我们将称之为BugZot的系统旨在提供此类功能。

应用将使用各种概念来构建系统,使其能够随着与系统交互的用户数量的增加而轻松扩展。我们将了解如何利用优化的数据访问和存储、高度可扩展的部署和缓存等各种技术来构建性能良好的应用,即使在高负载场景中也是如此。

在本章中,我们将了解:

  • 利用现有 web 框架构建企业级 web 应用
  • 实现对数据库访问的优化以加速应用
  • 实现缓存技术以减少应用后端的负载
  • 利用多线程技术提高应用并发性
  • 以可扩展的方式为生产部署应用

技术要求

本书中的代码清单可在chapter06目录下找到 https://github.com/PacktPublishing/Hands-On-Enterprise-Application-Development-with-Python.

可以通过运行以下命令克隆代码示例:

git clone https://github.com/PacktPublishing/Hands-On-Enterprise-Application-Development-with-Python

本章旨在构建一个可伸缩的 bug 跟踪 web 应用。为了实现这一点,我们使用了大量已经存在的库和工具,这些库和工具都是公开的,并且经过了良好的测试,以适应不同的用例。构建和运行演示应用需要以下工具集:

  • PostgreSQL 9.6 或以上版本
  • Python 3.6 或更高版本
  • Python 中 web 开发的 Flask 微框架。。。

定义需求

构建任何企业级应用的第一部分是定义应用的目标。到目前为止,我们知道我们的应用将跟踪欧米茄公司销售的各种产品的 bug。但是,我们的应用需要什么样的东西才能被证明对 bug 跟踪有用呢?让我们看一看并尝试定义我们要构建的应用的需求。

  • 对多个产品的支持:我们的缺陷跟踪系统的基本要求之一是支持对组织构建的多个产品的缺陷进行跟踪。考虑到组织的未来发展,这也是一个必需的特性。
  • 支持每个产品的多个组件:虽然我们可以在产品级别本身归档缺陷,但这太笨拙了,特别是考虑到大多数组织都有一个单独的团队处理产品的正交特性。为了使基于已归档组件的缺陷跟踪更容易,缺陷跟踪系统应支持在组件到组件的基础上归档缺陷。
  • 对附件的支持:很多时候,提交 bug 的用户,或者在 bug 生命周期中以任何方式涉及的用户,可能希望附加显示 bug 影响的图像,或者可能希望在 bug 上附加补丁,以便在将其纳入产品之前进行测试。这将需要 bug 跟踪系统为 bug 报告附加文件提供支持。
  • 评论支持:一旦缺陷被归档,负责解决该缺陷的用户可能需要关于该缺陷的其他信息,或者可能需要一些协作。这使得 bug 跟踪系统必须支持注释。此外,并非所有评论都可以公开。例如,如果开发人员可能已将某个补丁附加到 bug 报告中,由 bug 的原始提交人进行测试,但该补丁尚未纳入主产品中,那么开发人员可能希望将该补丁保持私有,以便只有具有特权访问权限的人才能看到它。这使得包含私人评论的功能也是必要的。
  • 支持多用户角色:并非组织中的每个人都有相同级别的漏洞跟踪系统访问权限。例如,只有主管级别的人员才能向产品中添加新组件,只有员工才能看到关于 bug 的私人评论。这要求将基于角色的访问作为系统的一项要求。

这些是特定于我们的 bug 跟踪系统的一些需求。然而,由于这些原因,系统中显然还需要包含一些其他需求。其中一些要求是:

  • 对用户认证系统的要求:系统应提供一种基于简单机制的用户认证机制。例如,用户应该能够通过提供用户名和密码,或电子邮件 id 和密码组合来登录系统。
  • 提交新 bug 的 Web 界面:应用应该提供一个简单易用的 Web 界面,用户可以使用该界面来提交新 bug。
  • 对 bug 生命周期的支持:一旦一个 bug 被归档到系统中,它的生命周期将以新的状态开始。从那里,当组织中的某个人拿起 bug 进行验证和复制时,它可能会转移到指定的状态。从那里,bug 可以进入各种状态。在我们的跟踪系统中,这被称为 bug 生命周期。我们的 bug 跟踪系统应该为这个生命周期提供支持,以及当 bug 从一种状态移动到另一种状态时如何处理它。

这样,我们终于有了我们的需求。当我们开始设计和定义如何构建 bug 跟踪 web 应用时,这些需求起着重要作用。因此,随着需求的到位,是时候让我们开始定义代码库的外观了。

进入发展阶段

随着项目结构的定义和到位,是时候开始开发我们的应用了。开发阶段包括各种步骤,包括设置开发环境、开发模型、创建映射到模型的视图以及设置服务器。

建立发展环境

在我们开始开发之前的第一步是建立我们的开发环境。这包括将所需的包准备到位,并设置环境。

设置数据库

我们的 web 应用在很大程度上依赖于数据库来管理与用户相关的个人记录和已归档的 bug。对于演示应用,我们将使用 PostgreSQL 作为数据库的选择。要在基于 RPM 的发行版(如 Fedora)上安装它,需要执行以下命令:

dnf install postgresql postgresql-server postgresql-devel

要在任何其他 Linux 发行版或任何其他操作系统(如 Windows 或 Mac OS)上安装postgresql,需要执行发行版/OS 所需的命令。

一旦我们安装了数据库,下一步就是初始化数据库,以便它可以用来存储我们的应用数据。用于设置。。。

建立虚拟环境

现在数据库就绪后,让我们建立虚拟环境,用于应用开发。要设置虚拟环境,让我们运行以下命令:

virtualenvpython=python3 

此命令将在当前目录中设置虚拟环境。建立虚拟环境后的下一件事是为应用开发和其他软件包安装所需的框架。

但是,在继续安装所需的软件包之前,让我们先通过执行以下命令激活虚拟环境:

source bin/activate

作为设计决策,我们将基于 Python Flask 微框架开发 web 应用。该框架是一个开源框架,已经存在了好几年了,并得到了各种插件的支持,这些插件可以很容易地随框架一起安装。该框架也是一个非常轻巧的框架,它附带了最少一组预先打包的模块,因此占用的空间更小。要安装flask,请执行以下命令:

pip install flask

安装 Flask 后,让我们通过执行以下命令来设置其他一些我们将在 web 应用开发中使用的必需软件包:

pip install flask-sqlalchemy requests pytest flask-session

至此,我们就完成了虚拟环境的设置。现在,让我们继续设置代码库的外观。

构建我们的项目

现在,我们正处于一个需要决定项目结构的阶段。项目结构非常重要,因为它决定了代码中不同组件之间的交互方式,以及应用的入口点。

一个结构良好的项目不仅有助于为项目提供更好的导航,还将有助于在代码的不同部分之间提供更高的一致性。

那么,让我们来看看我们的代码结构是如何看起来的,并理解特定目录或文件所代表的意义:

$ tree --dirsfirst├── bugzot│   ├── helpers│   │   └── __init__.py│   ├── models│   │   └── __init__.py│   ├── static│ ├── templates ...

初始化 Flask 项目

因此,我们终于进入了项目的有趣阶段,我们将从头开始构建这个项目。所以,让我们不要等待太久,我们才能看到一些行动。我们要做的第一件事是用 Flask 建立一个基本项目,并让它运行。要做到这一点,让我们启动代码编辑器并设置初始代码库。

让我们打开文件bugzot/application.py并初始化我们的应用代码库:

'''
File: application.py
Description: The file contains the application initialization
             logic that is used to serve the application.
'''
from flask import Flask, session
from flask_bcrypt import Bcrypt
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy

# Initialize our Flask application
app = Flask(__name__, instance_relative_config=True)

# Let's read the configuration
app.config.from_object('config')
app.config.from_pyfile('config.py')

# Let's setup the database
db = SQLAlchemy(app)

# Initializing the security configuration
bcrypt = Bcrypt(app)

# We will require sessions to store user activity across the application
Session(app)

在这里,我们已经完成了应用的基本设置。让我们花点时间来理解我们在这里做了什么。

在文件的一开始,我们首先导入了我们将在其上构建项目所需的包。我们从包flask中导入了Flask应用类。类似地,我们导入代码散列库bcryptFlask会话类和 Flask 的 SQLAlchemy 支持包,该支持包提供 SQLAlchemy 与 Flask 的集成。

一旦我们导入了所有必需的包,接下来的事情就是初始化我们的 Flask 应用。为此,我们创建了一个Flask类的实例,并将其存储在名为app的对象中。

app = Flask(__name__, instance_relative_config=True)

在创建这个实例时,我们向类构造函数传递两个参数。第一个参数用于表示烧瓶应用的名称。__name__提供,我们将其作为应用名传递给构造函数。第二个参数instance_relative_config允许我们覆盖实例文件夹中的应用配置。

通过这个,我们完成了 Flask 应用实例的设置。下一件事是加载应用的配置,它将用于配置应用中不同组件的行为方式,以及如何向用户提供应用。为此,我们需要读取配置文件。以下两行实现了这一点:

app.config.from_object('config')
app.config.from_pyfile('config.py')

第一行加载项目根目录下的config.py文件,将其视为对象,并加载其配置。第二行负责读取实例目录下的config.py文件,并加载其中可能存在的任何配置。

一旦加载了这些配置,它们就可以在app.config对象下使用。大多数 Flask 插件都配置为从app.config读取配置,因此,如果每个插件都有不同的机制来处理配置,那么就可以减少可能发生的混乱。

在应用中加载配置后,我们现在可以继续初始化可能需要的其余模块。特别是,我们需要更多的模块来建立我们的应用功能。这些模块包括 SQLAlchemy 引擎,我们将使用它来构建数据库模型并与之交互;会话模块,需要它来管理整个应用的用户会话;以及bcrypt模块,需要它来提供整个应用的加密支持。以下代码行提供了此功能:

db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
Session(app)

正如我们从这些代码行中看到的,要配置这些模块,我们所需要做的就是将 Flask 应用对象作为参数传递给相应的类构造函数,它们的配置将从那里获取。

现在,我们已经准备好了应用初始化代码,接下来我们需要做的事情是从 BugZot 模块导出所需的组件,以便可以从项目根调用应用。

要实现这一点,我们需要做的就是将这些模块包括在模块入口点中。那么,让我们启动代码编辑器并打开bugzot/__init__.py,在那里我们需要获取这些对象。

'''
File: __init__.py
Description: Bugzot application entrypoint file.
'''
from .application import app, bcrypt, db

我们完成了。我们在 BugZot 模块中导出了所有必需的对象。现在,问题是如何启动我们的应用。因此,要启动我们的应用并使其服务于传入的请求,我们需要完成更多的步骤。因此,让我们打开项目根目录中的run.py文件,并在其中添加以下行:

'''
File: run.py
Description: Bugzot application execution point.
'''
from bugzot import app

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

我们完成了。那不是很简单吗?我们在这里所做的只是导入我们在 BugZot 模块中创建的flask应用对象,并调用app对象的run方法,将应用将在其上为用户服务的hostname的值以及应用服务器应绑定以侦听请求的端口传递给它。

我们现在都准备好启动应用服务器,让它监听传入的请求。然而,在我们这样做之前,我们只需要再完成一个步骤,即为应用创建配置。那么,让我们开始创建配置。

创建配置

在启动应用之前,我们需要配置要在应用中使用的模块。因此,让我们首先在代码编辑器中打开config.py并向其中添加以下内容,从而创建应用的全局配置:

'''File: config.pyDescription: Global configuration for Bugzot project'''DEBUG = FalseSECRET_KEY = 'your_application_secret_key'BCRYPT_LOG_ROUNDS = 5 # Increase this value as required for your applicationSQLALCHEMY_DATABASE_URI = "sqlite:///bugzot.db"SQLALCHEMY_ECHO = FalseSESSION_TYPE = 'filesystem'STATIC_PATH = 'bugzot/static'TEMPLATES_PATH = 'bugzot/templates'

有了这些,我们起草了我们的全局应用配置。让我们试着。。。

开发数据库模型

数据库模型是任何实际应用不可或缺的一部分。这是因为企业中任何严肃的应用都肯定会处理某种需要跨时间持久化的数据。

我们的混蛋也是如此。BugZot 用于跟踪 Omega 公司产品中遇到的 bug 及其生命周期。此外,应用还必须保留在其上注册的用户的记录。为了实现这一点,我们需要多个模型,每个模型都有自己的用途。

对于该应用的开发,我们将所有相关模型分组在各自的单独目录下,以便我们能够清楚地了解哪些模型用于什么目的。此外,这使我们能够保持代码库整洁,避免混乱,这可能使开发人员很难理解未来随着代码库的增长每个文件的功能。

因此,让我们首先开始开发管理用户帐户相关信息所需的模型。

为了开始开发与用户帐户相关的模型,我们首先在模型目录中创建一个名为users的目录:

mkdir bugzot/models/users

然后将其初始化为模型模块内的子模块。

完成后,我们就可以开始创建用户模型,其定义如以下代码所示:

'''
File: users.py
Description: The file contains the definition for the user data model
             that will be used to store the information related to the
             user accounts.
'''
from bugzot.application import db
from .roles import Role

class User(db.Model):
    """User data model for storing user account information.

    The model is responsible for storing the account information on a
    per user basis and providing access to it for authentication
    purposes.
    """

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(50), unique=True, index=True, nullable=False)
    password = db.Column(db.String(512), nullable=False)
    email = db.Column(db.String(255), unique=True, nullable=False, index=True)
    user_role = db.Column(db.Integer, db.ForeignKey(Role.id))
    role = db.relationship("Role", lazy=False)
    joining_date = db.Column(db.DateTime, nullable=False)
    last_login = db.Column(db.DateTime, nullable=False)
    account_status= db.Column(db.Boolean, nullable=False, default=False)

    def __repr__(self):
        """User model representation."""
        return "<User {}>".format(self.username)

有了这个,我们就创建了我们的用户模型,可以用来存储与我们的用户相关的信息。大多数列只提供我们希望存储在数据库中的数据的定义。但是,这里有几个有趣的地方,让我们来看看:

index=True

我们可以看到用户名和电子邮件列定义中提到了此属性。在这两列中,我们将 index 属性设置为 True,因为这两列可以经常用于访问与特定用户相关的数据,因此可以受益于索引带来的附加优化。

下一个有趣的信息是到角色模型的关系映射。

role = db.relationship("Role", lazy=False)

由于数据库中的每个用户都有一个与其关联的角色,因此我们可以添加一个从用户模型到角色模型的一对一关系映射。另外,如果我们仔细看一下,我们已经设置了lazy=False。这里有一个小原因可以解释为什么我们要避免延迟加载。角色模型通常很小,从用户模型到角色模型只有一对一的映射。通过避免延迟加载,如果我们的数据库访问层延迟加载角色模型中的数据,我们将减少一些等待时间。现在,问题来了,榜样在哪里?

角色模型的定义可以在bugzot/models/users/roles.py文件中找到,但为了保持本章的简洁,我们在书中没有明确提供该定义。

此外,我们还需要一种机制来验证用户的电子邮件地址。我们可以向用户发送一封包含激活链接的小电子邮件,用户需要点击该链接。为此,我们还必须为每个新用户生成并存储一个激活密钥。为此,我们利用了一个名为ActivationKey模型的新模型,其定义可以在bugzot/models/users/activation_key.py文件下找到。

一旦所有这些都完成了,我们现在就可以从我们的用户模型子模块中导出这些模型了。为此,让我们在代码编辑器中启动模块入口点文件,并通过在bugzot/models/users/__init__.py文件中添加以下行来导出模型:

from .activation_key import ActivationKey
from .roles import Role
from .users import User

这样,我们就完成了与存储用户信息相关的数据模型的定义。

在我们的应用中,下一件事是定义与产品分类相关的数据模型,这些产品可以被归档。那么,让我们开始创建与产品分类相关的模型。

为了创建与产品相关的模型,我们首先在bugzot/models模块下创建一个新的子模块目录并初始化它。接下来,我们提供bugzot/models/products/products.py下的产品模型定义,如下代码所示:

'''
File: products.py
Description: The file contains the definition for the products
             that are supported for bug filing inside the bug tracker
'''
from bugzot.application import db
from .categories import Category

class Product(db.Model):
    """Product defintion model.

    The model is used to store the information related to the products
    for which the users can file a bug.
    """

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    product_name = db.Column(db.String(100), nullable=False, unique=True, index=True)
    category_id = db.Column(db.Integer, db.ForeignKey(Category.id))
    category = db.relationship("Category", lazy=True)

    def __repr__(self):
        """Product model representation."""
        return "<Product {}>".format(self.product_name)

有了这一点,我们已经完成了产品模型的定义,该模型将用于跟踪产品,根据该模型,可以在我们的应用中归档缺陷。

我们的产品子模块中还有一些模型定义,如下所示:

  • 类别:类别模型负责存储特定产品所属的产品类别信息
  • 组件:组件模型负责存储与产品组件相关的信息,针对这些信息可以提交 bug
  • 版本:版本模型负责存储与产品版本相关的信息,根据这些信息可以对 bug 进行分类

一旦定义了所有这些模型,就可以从产品的子模块中导出它们,以便在应用中使用它们。

以类似的方式,我们定义了与跟踪系统内部缺陷相关的模型。为了保持章节长度的合理性,我们将跳过在本章中提及这些模型的定义,但是,对于好奇的人来说,这些模型的定义可以很容易地在本章代码库的 bugzot/models/bugs 目录中进行跟踪。

迁移数据库模型

在创建了数据库模型并准备好使用之后,下一步就是将这些数据库模型迁移到我们用来运行应用的数据库服务器上。这样做的过程非常简单。

要将模型迁移到数据库服务器,我们首先将它们公开到应用根目录中。例如,要迁移与用户和产品相关的数据库模型,只需在bugzot/__init__.py文件中添加以下行:

from bugzot.models import ActivationKey, Category, Component, Product, Role, User, Version

完成后,我们需要做的就是调用我们创建的 SQLAlchemy 数据库对象的create_all()方法。这可以通过添加以下内容来完成。。。

构建视图

一旦模型生成并准备好使用,我们需要的下一件事就是拥有一种机制,通过这种机制我们可以与这些模型交互,以便访问或修改它们。实现此功能的方法之一是使用视图。

使用 Flask,构建视图是一项相当简单的任务。Flask web 框架为构建视图提供了多种方法。实际上,/ping端点也可以被称为仅使用过程样式构建的视图之一。

在本例的过程中,我们现在将尝试遵循面向对象的方法,同时定义应用中的任何资源。那么,让我们继续并开始发展我们的一些观点。

开发索引视图

每当用户访问我们的应用时,最有可能的情况是用户将登录到应用的主页。因此,我们构建的第一件事是索引视图。这也是我们可以理解如何在 Flask 中构建简单视图的地方之一。

因此,作为第一步,让我们通过执行以下命令,在项目工作区的 views 目录中为索引模块创建一个新模块:

mkdir bugzot/views/indextouch bugzot/views/index/__init__.py

有了这些,我们现在准备编写第一个视图的代码,代码如下:

'''File: index.pyDescription: The file provides the definition for the index view             which is used to render the homepage of Bugzot.'''from bugzot.application ...

获取要渲染的索引视图

现在,我们已经准备好了索引视图。但是,在将该视图提供给用户之前,我们需要为 Flask 提供一个关于该视图将在其上呈现的端点的映射。为了实现这一点,让我们启动我们的代码编辑器并打开bugzot/__init__.py并在文件中添加以下行:

from bugzot.views import IndexView
app.add_url_rule('/', view_func=IndexView.as_view('index_view'))

这里,我们的重点是第二行,它负责将视图映射到 URL 端点。flask 应用的add_url_rule()负责提供这些映射。该方法将视图应在其上呈现的 URL 路径作为其第一个参数。提供给方法的view_func参数接受需要在提供的 URL 端点上呈现的视图。

完成后,我们现在就可以为索引页提供服务了。我们现在需要做的就是运行以下命令:

python run.py

然后访问http://localhost:8000/ 在您的浏览器上。

构建用户注册视图

现在,随着索引视图的部署和使用准备就绪,让我们继续构建一个更复杂的视图,允许用户在 BugZot 上注册。

下面的代码实现了一个名为UserRegisterView的视图,它将允许用户注册到 BugZot。

'''File: user_registration.pyDescription: The file contains the definition for the user registration             view allowing new users to register to the BugZot.'''from bugzot.application import app, brcypt, dbfrom bugzot.models import User, Rolefrom flask.views import MethodViewfrom datetime import datetimefrom flask import render_template, sessionclass UserRegistrationView(MethodView):    """User registration view to allow new user registration. The user ...

部署以实现并发访问

到目前为止,我们还处于开发阶段,可以很容易地使用 Flask 附带的开发服务器来快速测试我们的更改。但是,如果您计划在生产环境中运行应用,那么这个开发服务器不是一个好的选择,我们需要一些更专门的东西。这是因为,在生产环境中,我们将更加关注应用的并发性及其安全方面,如启用 SSL 和提供对某些端点的更受限访问。

因此,我们需要在这里找到一些选择,因为我们需要应用处理大量并发访问,同时不断为用户保持良好的响应时间。

考虑到这一点,我们最终会有以下一组选择,从本质上讲,这些选择在许多生产环境中也相当常见:

  • 应用服务器:Gunicorn
  • 反向代理:Nginx

在这里,Gunicorn 将是负责处理 Flask 应用提供的请求的应用,而 Nginx 负责请求队列和处理静态资产的分配。

因此,首先,让我们设置 Gunicorn,以及如何通过它为应用提供服务。

设置 Gunicorn

Gunicorn 安装的第一步是安装,这是一项非常简单的任务。我们只需运行以下命令:

pip install gunicorn

完成后,我们就可以运行 Gunicorn 了。Gunicorn 通过代表 Web 服务器网关接口的WSGI运行应用。为了让 Gunicorn 运行我们的应用,我们需要在我们的项目工作区中创建一个名为wsgi.py的附加文件,该文件包含以下内容:

'''File: wsgi.pyDescription: WSGI interface file to run the application through WSGI interface'''from bugzot import appif __name__ == '__main__':    app.run()

一旦我们定义了接口文件,我们所需要做的就是运行下面的命令使 Gunicorn。。。

将 Nginx 设置为反向代理

要使用 Nginx 作为反向代理解决方案,我们首先需要在系统上安装它。对于基于 Fedora 的发行版,可以通过运行以下命令,使用基于dnfyum的包管理器轻松安装:

$ sudo dnf install nginx

对于其他发行版,可以使用其包管理器安装 Nginx 包。

一旦安装了 Nginx 包,我们现在需要对其进行配置,以允许它与应用服务器通信。

要配置 Nginx 代理通信到我们的应用服务器,请在/etc/nginx/conf.d目录下创建一个名为bugzot.conf的文件,包含以下内容:

server {
    listen 80;
    server_name <your_domain> www.<your_domain>;

    location / {
        include proxy_params;
        proxy_pass http://unix:<path_to_project_folder>/bugzot.sock;
    }
}

现在配置了 Nginx 之后,我们需要在 Gunicorn 应用服务器和 Ngnix 之间建立关系。那么,让我们开始吧。

在 Nginx 和 Gunicorn 之间建立沟通

我们刚刚完成的 Nginx 配置中需要注意的一点是proxy_pass行:

proxy_pass http://unix:<path_to_project_folder>/bugzot.sock

该行告诉 Nginx 寻找一个套接字文件,Nginx 可以通过该文件与应用服务器通信。我们可以告诉 Gunicorn 为我们创建这个代理文件。这可以通过执行以下命令来完成:

gunicornbind unix:bugzot.sock -m 007 wsgi:app

执行此命令后,我们的 Gunicorn web 服务器将创建一个 Unix 套接字并绑定到它。现在,剩下的就是启动我们的 Nginx web 服务器,这可以通过执行以下命令轻松实现:

systemctl start nginx.service

一旦这样做了。。。

总结

在本章中,我们获得了如何开发和托管企业级 web 应用的实践经验。为了实现这一点,我们首先要做一些关于我们将使用哪些 web 框架和数据库的技术决策。然后,我们开始定义项目结构以及它在磁盘上的外观。其主要目的是实现高模块性和代码之间的低耦合。一旦定义了项目结构,我们就初始化了一个简单的 Flask 应用,并实现了一个路由来检查服务器是否工作正常。我们后来继续定义我们的模型和视图。一旦定义了这些,我们就修改了应用,以启用新的路由来访问我们的视图。一旦我们的应用开发周期结束,我们就开始了解如何使用 Gunicorn 和 Nginx 部署应用来处理大量请求。

现在我们继续下一章,我们将了解如何为正在开发的应用开发优化的前端,以及前端如何在与应用交互时影响用户体验。

问题

  • Flask 提供的其他一些预构建视图类是什么?
  • 我们可以从用户表中删除对角色表的外键约束而不删除关系吗?
  • 除了 Gunicorn 之外,为应用提供服务的其他选项有哪些?
  • 我们如何增加 Gunicorn 工人的数量?