使用蓝图和应用工厂在Flask中构建大型应用程序
软件开发人员采用各种技术来构造Flask应用程序。然而,在构建小型或中型应用时,这种应用的结构可能不是非常重要,尤其是在使用包结构技术时。
在构建大型应用程序时,使用包结构来构建应用程序将导致代码库毫无技巧可言,从而不可避免地导致循环导入等问题。
为了避免大型应用结构化不完善导致的障碍,在用Flask构建应用时主要使用两种技术,即。蓝图和应用工厂。
前提条件
这篇文章的先决条件包括对以下概念的理解。
- Flask网络应用的中级使用和实现
- 了解Python的面向对象编程概念
- 了解Flask的视图和模板
- 对终端使用的中级知识
- 对数据库的中级理解
工作环境设置
在本教程中,推荐使用PyCharm集成开发环境,因为它具有建立一个基本应用程序所需的所有功能。
然而,如果你在IDE方面有不同的偏好,那么你应该考虑安装一个虚拟环境并安装Flask。
为了保持本文介绍部分的简洁,我不会介绍如何设置Flask的Web应用。
考察基本的Flask应用结构
在我们深入研究大规模Flask应用的结构之前,首先让我们了解一下一个基本的Flask应用是如何结构的。
为了考察Flask网络应用的基本结构,让我们在这里克隆这个仓库。
在克隆的版本库中,我们有app.py 文件,static 文件夹,以及templates 文件夹。app.py 文件由app route 和run 语句组成,而static 文件夹存储了我们在构建 Web 应用程序时需要的 CSS、JS 和图片文件。Templates文件夹包括要呈现给用户的HTML文件。
作为一个中级开发者,运行这个应用程序将导致在你的网络浏览器上打印出一个 "Hello World "语句。虽然这种基本的应用程序结构足以构建小规模的应用程序,但如果我们需要开始实现额外的功能,如认证、电子邮件、错误、数据库、用户资料,以及根据应用程序的需要实现更多的功能,会发生什么情况。
事实证明,如果在app 文件夹中为每个功能编写代码,或者在没有适当结构的情况下将每个功能的所有HTML文件存储在模板目录中,这将导致冲突,也会使调试变得困难。
为了避免用flask的基本结构构建大规模应用程序的弊端,我们需要了解Blueprints和Application Factory。
蓝图简介
蓝图有助于将我们的Web应用程序的组件组织成不同的组件。蓝图的定义并不能完全说明它是如何工作的,让我们以一个web应用为例。
在一个网络应用程序中,我们有注册组件和用户资料组件。我们可以给每个组件分配一个唯一的标识符,这样任何子组件都可以用其基础组件的唯一标识符进行引用。
例如,注册组件可以用一个名为*"Reg "*的蓝图来注册,然后任何模板、视图都可以通过蓝图名称来访问,同样的事情也适用于用户配置文件组件。
与基本应用结构相比,蓝图的优势在于基本应用结构利用一个view.py 文件来存储Web应用的所有视图和路由。
然而,这样做的问题是,如果我们为注册和用户资料组件都有一个索引路由,那么当用户导航到任何一个组件时,Flask如何知道要加载哪个路由?它不知道,但通过蓝图,它可以知道。
蓝图代码示例
让我们按部就班地为*"认证 "创建一个简单的蓝图。*
要为一个特定的功能或组件创建蓝图,为它起一个简短的名字是一种可靠的设计方法,在开发者社会中,认证也通常被称为*'auth'。*
首先,我们在Flask应用程序中创建一个包,并将其命名为*"auth"。*
注意,一个包必须用
__init__.py文件来初始化。我们也可以添加视图和表单文件,但要确保它们的前缀是包的名称,例如:auth_views.py,和auth_form.py
接下来,在__init__.py 文件中,我们导入蓝图并创建一个蓝图对象,变量为auth ,然后在蓝图对象下面,我们导入视图、表单和其他文件。
你的auth __init__.py 文件应该看起来像这样。
from flask import Blueprint
auth = Blueprint('auth', __name__)
from . import auth_forms, auth_views
现在我们已经创建了蓝图,我们需要注册它们。为了注册我们的蓝图,我们需要创建一个应用程序工厂。因此,让我们继续介绍一下应用工厂的情况。
应用工厂的介绍
应用工厂是一个封装创建应用对象并返回的函数。这种结构化Flask应用程序的模式为开发者提供了独特的灵活性,可以为同一个应用程序加载不同的配置文件。
在整个Flask应用程序的实例化和配置过程中,蓝图和其他扩展都是在一个叫做应用程序工厂的函数中处理的。
使用这种方法来实例化应用程序的扩展和组件,可以确保开发人员在实例化应用程序之前对其进行配置,这就解决了循环导入的问题。
应用程序工厂代码示例
应用程序工厂的形式是一个通常称为create_app 的函数。它接受配置参数。然后,函数的主体将flask应用和应用配置实例化。
应用程序工厂函数还通过init_app 方法初始化扩展实例,该方法可用于初始化应用程序,同时接收flask应用程序的参数app 。
请注意,应用程序所需的所有扩展都以上述格式进行实例化。
最后,应用程序工厂功能的最后一个组成部分是蓝图注册。在这里,我们导入应用程序的各个蓝图组件,并通过register_ blueprint() 方法注册它们。
下面是应用工厂的代码模板。
def application_factory_method(config):
app = Flask(__name__)
#load application configuration from its object
app.config.from_object(config)
#initialize installed extension instances
#as an example, initialize database extension
db.init_app(app)
db.app = app
#as an example, initialize flask mail extension
mail.init_app(app)
Mail.app = app
#register blueprints of applications
#from app.blueprint_package import blueprint_object as dummy_name
# register blueprint
#code sample using the auth blueprint sample
from app.auth import auth as auth_bp
app.register_blueprint(auth_bp)
#return the app object
return app
以上是应用工厂的实现的代码模板。在文章的最后一节,我们将把应用程序的所有组件放在一起,以了解大型应用程序在Flask中是如何结构化的。
让我们继续处理应用程序的配置和环境变量。
使用配置和环境变量
配置变量是我们应用程序的必要参数,它们从我们的环境变量中检索敏感信息。因此,我们需要为应用程序的范围访问所需的变量,而不需要在运行时单独加载和设置这些变量。
对于配置变量的重要性,一个很好的比喻是当我们想运行你的应用程序的不同状态时。例如,在一个生产环境中,我们需要将调试设置为false,数据库统一资源标识符,以及其他针对生产环境的配置变量。
开发者也希望为测试环境和开发环境提供独特的配置参数。
配置文件代码示例
在处理flask网络应用程序的配置参数时,我们需要在网络应用程序的基础目录下创建一个config .py 文件。在我们的配置文件中,我们将与os包一起工作,因此必须导入它。
我们还需要将基础目录设置为路径目录名的绝对路径,这应该是这样的。
import os
basedir = os.path.abspath(os.path.dirname(__name__))
下一步是创建一个Config的超类,它继承了类对象。
然后,Config类本身就是对象类的基类,它不接受任何参数,并返回一个没有任何实例属性的新实例。
Config超类接受某些属性,即秘钥和一些数据库配置属性。秘密密钥属性将从应用程序环境中获取,这在我们开始处理环境配置时就会变得很清楚。配置类应该看起来像这样。
# Create the super class
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
SQLALCHEMY_TRACK_MODIFICATIONS = False
接下来,我们需要创建继承超级类config的每个config类。
在Web开发中,有三个标准的配置类,即开发配置、测试配置和生产配置。为了节省时间,配置设置应该是这样的。
# Create the development config
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///'+os.path.join(basedir, 'dev-data.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = os.environ.get('MAIL_PORT')
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS')
MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL')
# Create the testing config
class TestingConfig(Config):
DEBUG = False
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'test-data.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
# create the production config
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
上面的代码封装了配置文件的基本模板,作为开发者,你可以自行决定每个配置(生产、开发和测试)下的内容。让我们继续讨论环境变量。
环境文件代码示例
环境变量文件存储在我们的Web应用程序的基本目录中。然而,为了使用环境变量,我们必须通过 pip 安装python-dotenv扩展。
pip install python-dotenv
一旦我们安装了dotenv扩展,在我们应用程序的基本目录中创建一个.env 文件。在.env 文件中,我们创建我们的应用程序需要的变量名称,并给它们分配一个默认值,这样我们就不必在每次运行我们的Web应用程序时给这些环境变量分配一个值了。
同样关键的是,包含敏感数据的变量最好存放在环境中(不能被公众阅读和访问)。其中一些变量是FLASK_APP,SECRET_KEY,MAIL_SERVER 和其他开发者需要的变量。
下面是一个.env 文件内容的例子。
FLASK_APP = 'run.py'
FLASK_ENV = development
FLASK_DEBUG = True
SECRET_KEY = '2a43ca5b42240a33dadc64beace65d1f'
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 465
MAIL_USERNAME = ‘demodeveloper@gmail.com'
MAIL_PASSWORD = ‘demodeveloperpassword’
我们已经成功地剖析了组成一个大规模应用程序的各个部分。现在,让我们继续把拼图的碎片放在一起,构建一个演示的社交网络应用。
构建一个大规模的应用程序
我们现在明白了构建一个大型Flask应用程序的组成部分。现在,让我们把这些碎片放在一起,了解如何构建一个。
构造一个大型Flask应用的过程非常简单明了。我们所需要的是以下内容。
- 配置文件
- .env文件
- 应用程序的功能/组件
- 使用蓝图
- 在应用程序工厂中实现蓝图
- 运行文件
我们也知道如何创建一个配置文件和一个环境变量文件。
然而,让我们来介绍一下如何处理我们应用程序的组件,然后将它们与蓝图和应用程序工厂结合起来。最后,我们实现结构并对运行文件进行编码。
我们应用程序的组件
当构建我们应用程序的一个组件或一个功能时,我们需要做的第一件事是为该组件创建一个包。
例如,在一个社交网络应用中,我们有用户认证功能;所以我们为用户认证创建一个包,这在网络开发中通常被认为是auth 。
在我们的auth包中,我们可以为这个特定的功能添加视图和表单文件。最好的做法是将功能名称作为包内文件的前缀。例如,views.py 的auth将被保存为auth_views.py ,这样可以方便识别。
在 auth 包中的__init__.py 文件中,我们需要做以下事情。
- 从flask导入蓝图
- 初始化一个蓝图对象,并传入这个特定组件的蓝图名称,在我们的例子中是 "Auth"。
- 在对象初始化的下面,我们在这里导入这个包/功能的所有其他组件,如
auth_forms,auth_views等。
这方面的完整实现如下。
from flask import Blueprint
auth = Blueprint('auth', __name__)
from . import auth_forms, auth_views, auth_utils
应用程序工厂
在创建了我们应用程序的组件并设置了蓝图后,我们必须在应用程序工厂方法中注册蓝图。
在我们的应用程序文件夹中,我们有应用程序本身的__init__.py 文件,我们导入我们的应用程序运行所需的所有扩展和模块。我们还为我们安装的扩展创建实例。
接下来,我们创建一个通常称为create_app() 的应用程序工厂函数。create_app() 函数从我们的config.py 文件中获取一个配置参数。下面概述了进入应用程序工厂函数的代码块的过程。
- 创建一个应用程序变量并初始化Flask
- 将应用程序配置作为对象从
config.py传递到函数中。 - 初始化在我们的应用工厂函数之外创建的扩展实例
- 注册蓝图
- 返回应用程序变量
这个逻辑的实现如下。
from flask import Flask
from config import DevelopmentConfig
from flask_mail import Mail
#instances of extensions
Mail = Mail()
#creating the application factory
def create_app(config=DevelopmentConfig):
app = Flask(__name__)
app.config.from_object(config)
#initialization of extension instances
mail.init_app(app)
mail.app = app
# register the authentication blueprint
from app.auth import auth as auth_bp
app.register_blueprint(auth_bp)
return app
运行文件
运行文件是我们运行flask应用程序的代码说明。
在这里,我们要做以下工作。
- 从应用中导入应用工厂
- 导入应用程序的配置类
- 创建一个应用程序的实例,并将其传递给应用程序的变量名
- 创建主块来运行应用程序
这个代码指令的实现如下。
# import the create app application factory
from app import create_app
# import the application config classes
from config import DevelopmentConfig, ProductionConfig, TestingConfig
app = create_app()
if __name__ == '__main__':
app.run()
结语
这篇文章涵盖了构造大型应用程序的所有方面,并为各个组件提供了独特的视角。虽然没有这个应用程序的代码库,但我觉得在大型应用程序中考察这种结构化应用模式的实现是一个巨大的学习经验。
你的目标是检查代码是如何连接的,并创建一个你的个人笔记,说明你如何最好地理解它,然后为你的个人发展结构一个大型的应用程序。