第125天:Flask 项目结构

简介: 第125天:Flask 项目结构

前面我们了解了 Flask 框架的特性和一些用法,比如创建一个简单应用、做些页面,以及增加鉴权模块等,如果要将 Flask 用于实际项目开发,还需要了解一下 Flask 项目结构。

Flask 是一个轻量级的 Web 框架,扩展性强,灵活性高,容易上手,不过 Flask 没有给出明确的项目结构,而是让开发者根据实际需求,创建适合自己的项目结构。对于初学者来说,面临的困难可能是不知道如何组织代码,特别是在看一些别人的代码时,弄不清结构,对理解和学习造成一定障碍。


需要说明的是今天所介绍的结构并不是最好的,不同的项目,不同的团队,不同的理念,会有不同的结构,今天介绍的只是一个参考。


我们就那之前的 Flask数据持久化 章节的练习作为实践。


按功能组织


按功能,指的是将 Web 项目的不同职能划分开,比如路由部分、模型部分、业务逻辑部分等


目录结构


project/  forms/    myform.py    ...  models/    __init__.py    profile.py    user.py    ...  routes/    __init__.py    home.py    profile.py    ...  static/    ...  services/    __init__.py    ...  templates/    createprofile.html    profile.html    ...  __init__.py  config.py


可以看到,项目根目录下,分为:


  • forms(表单):存放表单对象
  • models(模型):存放数据模型,即库表在程序中的映射对象,以及对象之间的关系
  • routes(路由):存放请求路由以及处理逻辑
  • static(静态文件):Flask 约定存放静态文件的目录
  • templates(模板):Flask 约定存放页面模板的目录
  • services(服务):存放业务逻辑或者其他服务类功能
  • __init__.py:Flask app 初始化方法
  • config.py:项目配置文件


这样的分类,相当于将之前写到一个代码文件(app.py)中的逻辑,按功能划分开,当项目逐渐变大变复杂后,这样的划分有助于开发和维护


初始化


按功能划分开,比较容易理解,不过将分开的部分有机结合起来是个问题, 推荐的方式是,在每个目录下创建一个 __init__.py 文件,有两个作用:


  1. 将目录变为包(package),方便其他地方引入


  1. 做些初始化工作,例如将目录下的内容统一起来,提供一站式装载


初始化模型


数据模型放在 models 目录下,一般数据模块需要和数据库交互,另外每个模型需要有个数据库实例,来创建模型以及字段定义


首先,创建目录的 __init__.py 代码文件:



from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def init_app(app):    db.init_app(app)    return db


  • 使用之前了解过的 Sqlalchemy 库,做数据映射(ORM)框架
  • 定义一个数据库对象 db,注意构造方法没有传递 app 参数,是因为此时还得到 app
  • 定义一个 init_app 函数,接收一个参数 app,就是 Flask app,用 db.init_app 方法初始化 Flask app


模型代码示例 project/models/profile.py


from . import db
class Profile(db.Model):    id = db.Column(db.Integer, primary_key=True)    name = db.Column(db.String(20))    birthday = db.Column(db.Date())    createtime = db.Column(db.DateTime())    about = db.Column(db.Text())


  • 因为是在 models 目录下的代码文件,所以通过当前目录引入在 __init__.py 中定义的 db,用来定义数据模型及其字段


  • 字段在前面的数据持久化中有详细说明,这里省略解释


初始化路由


当路由处理代码被分开之后,在主程序代码中初始化会变得比较麻烦,幸好 Flask 有个 blueprint(蓝图)的概念,能很好的将分离出来的代码管理起来,确切的说 blueprint 的作用不止于此,这里只是需要用到它的部分功能


Web 项目被分成多个部分之后,每个部分可以单独成为一个子应用,blueprint 的作用就是可以让子应用的编写方式用在主应用中一样,比如注册路由,处理请求等,使用前,先创建一个 blueprint 实例,然后再将实例注册到 Flask app 实例中就好了。

路由处理定义示例,project/routes/home.py:



from flask import Blueprint
home_bp = Blueprint('home_bp', __name__)
@home_bp.route('/', methods=['GET', 'POST'])def index():    return "Hello World!", 200


  • 引入 Flask 的 blueprint 模块
  • 初始化 blueprint 实例的实例 home_bp,第一个参数是 终端点(endpoint) 的名称,用在 url_for 方法中,第二个参数是作为模块被引入时候的名称
  • 使用和 blueprint 实例同名的装饰器定义路由,代替了之前 @app.route 的方式,相当于 blueprint 实例是一个 Flask app 实例
  • 视图函数的定义之前 Flask app 实例中的没有区别,这里只是简单的返回文字和状态

再看看路由模块的初始化,routes/__init__.py:



from .home import home_bpfrom .profile import profile_bp
def init_app(app):    app.register_blueprint(home_bp)    app.register_blueprint(profile_bp)


  • 从当前目录下引入具体路由文件,从中引入 blueprint 实例
  • 定义初始化方法,参数就是 Flask app 实例,用 register_blueprint 方法将 blueprint 注册到 Flask app 实例中


Flask app 工厂方法


在之前的介绍中,在 app.py 中编写所有的东西,并且通过 app.run() 来启动应用,在实际项目中,推荐用 app 工厂方法的方式来启动,好处是:


  1. 便于测试,可以在不同的测试用例中创建特别的 app 实体
  2. 多实例运行,如果需要一个应用的多个版本,可以在一个应用进程中运行多个实例,而不必部署多个 Web 服务器(将在 Flask 部署中介绍)


创建 Flask app 写在 project/__init__.py 中:



from flask import Flaskfrom .config import configfrom . import models, routes
def create_app(config_name='default'):    app = Flask(__name__)    app.config.from_object(config[config_name])    config[config_name].init_app(app)
    models.init_app(app)    routes.init_app(app)
    return app
  • 引入 flask 库
  • 从当前目录下引入配置文件
  • 引入上面定义的模型模块和路由模块
  • 定义工厂方法,默认方法名是 create_app,如果其他名称,需要在启动应用时指定(随后介绍),工厂方法有个参数,用来指定需要加载的配置内容,且设定了默认值(随后介绍)
  • 工厂方法中,先创建 Flask app 实例,然后加载配置,最后为模块初始化 模型和路由
  • 最后返回 Flask app 实例,方便测试和应用启动时的调用


工厂方法比单个文件写法更清爽,修改起来也更简单,另外这样定义还可以避免循环依赖问题,


循环依赖:如果在工厂方法中直接定义数据库模块 db,在模型中需要引用 db,而工厂方法又需要用模型来初始化 Flask app,就会引起循环依赖问题


启动项目


通过工厂方法创建的应用,因为没有明确的 app.run() 调用,不能直接像在前一样直接运行文件,而是要用 flask 命令行方式来启动


正常启动


启动之前,需要先设置 FLASK_APP 环境变量,指定需要运行的 Flask 项目, 值为项目文件夹名,即项目名:

  • Linux 或者 Mac


export FLASK_APP=project
  • Windows 命令行


set FLASK_APP=project
  • Powershell


$env:FLASK_APP="project"

然后在项目目录的上一层目录下执行命令,启动项目:


flask run

如果一切正常,就可以看到类似的结果:


* Serving Flask app "project" * Environment: production   WARNING: Do not use the development server in a production environment.   Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)


设置启动参数


前面工厂方法可以定义一些参数,如何来指定呢?其中一种方法是设置环境变量 FLASK_APP,例如将 congfig_name 参数设置为 testing:

  • Linux 或者 Mac


export FLASK_APP=project:create_app('testing')
  • Windows 命令行


set FLASK_APP=project:create_app('testing')
  • powershell


$env:FLASK_APP="project:create_app('testing')"
  • project 是 Flask app 所在的模块名,与上面直接写 project 一样
  • 冒号(:)后即为工厂方法的名,并且将参数带入


您可能已经想到,这种方式可以解决工厂方法名不是默认 create_app 的情况了,例如工厂方法名为 myapp_factory,以 Linux 环境为例:


export FLASK_APP=project:myapp_factory()


按业务组织


一个大型项目中,会包含很多子业务,比如人员管理、订单管理、统计报表等等,每一部分都可以是独立的项目,在 Flask 中,按照业务的方式将文件划分开,就是按业务方式来组织项目结构,这样的组织方式有助于并行开发和分而治之。


大体的结构是:


project/  __init__.py  config.py  db.py  auth/    __init__.py    route.py    models.py    templates/  blog/    __init__.py    route.py    models.py    templates/  ...


  • 项目结构中,__init__.pyconfig.py 是整个应用的
  • auth、blog 目录是子业务,可以看到每个内部有自己的路由、模型和模板文件夹
  • db.py 是数据库连接模块,为各个子业务提供统一的数据库连接和模型支持,因为是单独的数据库模块,所以不会出现前面说的循环依赖问题,需要使用数据库模块的地方直接导入就行。


按业务组织方式中,每个子业务都是以 blueprint 的方式注册到 Flask app 上的,在按功能组织的方式中,我们只将路由用 blueprint 注册了,其实可以将 blueprint 看成一个独立的 Flask app,不过不用真的去部署,只需要注册到真正的 Flask app 上就行。


项目配置


之前的练习中都是将配置写到 app.py 中的,只是为了方便练习。实际项目中,配置是很重要的部分,系统研发过程中,需要经历不同的环境,比如开发环境,测试环境和生产环境,如果配置错了,开发环境连接上了生产环境的数据库,那可就糟糕了,相反开发环境为了方便查错,往往开启了 Debug 模式,如果放在生产环境中将会带来很大的性能损耗。


Python 中提供了丰富的配置处理方式,今天就 Flask 的配置利用实例简单介绍下,不过介绍的不见得就是最好的,只是一种解决思路,大家可以根据具体项目有所调整。


看一下代码:


import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    @staticmethod    def init_app(app):        pass
class DevelopmentConfig(Config):    DEBUG = True    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-dev.db')
class TestingConfig(Config):    TESTING = True    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-test.db')
class ProductionConfig(Config):    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data.db')
config = {    'development': DevelopmentConfig,    'testing': TestingConfig,    'production': ProductionConfig,
    'default': DevelopmentConfig}


  • 实例项目中使用的数据库是 Sqlite,需要指定数据库文件目录,所以在定义了统一的目录 basedir,获取的是项目所在文件夹目录,因为 config.py 就在项目根目录中
  • 定义了 Config 基类,用类属性设置了 Flask app 的一些配置,其中 init_app 是为了在初始化 app 是附加一些额外配置用的
  • 定义了三个不同场景下的配置子类,分别是开发环境、测试环境和生产环境,大同小异,特别需要注意的是数据库文件名称,不同的场景有不同的名称
  • 将不同的配置放在一个词典(dict)中,在 Flask app 工厂方法中,通过参数来选择具体的配置类,为了严谨,还设置的默认配置,显然默认为开发环境是很好的选择


有必要说明的是,Flask app 有多种设置配置的方式,常用的如:


  • 属性指定,如 app.config["MYCONFIG"] = "xxxx"
  • 对象获取,如 app.config.from_object(configObj)
  • 配置文件,app.config.from_pyfile(pyfilepath)
  • JSON,app.config.from_json(jsonfilename)


总结


今天介绍了一个简单的 Flask 项目化结构,并利用之前做过的数据持久化的练习,做了项目化后的代码说明,并且说明了按功能和按业务两种项目组织方式,最后介绍了 Flask 项目中配置的方式。总之 Flask 是一个宽松的,简单的 Web 框架,每个人都可打造自己的一套项目构建方式,不过对于刚开始接触的同学,或者为了交流方便,还是有必要了解一下一般的组织方式,希望对您有所启发。


最后,示例代码中提供了较为完整的例子,其中还有如何自定义数据库初始化命令的例子,请您参考。

目录
相关文章
|
6月前
|
缓存 前端开发 JavaScript
flask各种版本的项目,终端命令运行方式的实现
flask各种版本的项目,终端命令运行方式的实现
276 4
|
6月前
|
数据可视化 API 开发者
通俗易懂:一步步教你 Flask 项目自动生成 API 文档
Flasgger,作为一款强大的 Flask 扩展,自动从 Flask 应用中提取并生成 OpenAPI 规范文档,配备 SwaggerUI,为开发者提供了一条快捷通道,让 API 的文档编制和交互式测试变得简单易行。Flasgger 的设计原则是简化开发流程,通过与 Flask 框架的无缝整合,让开发者可以更专注于应用逻辑的构建。
|
前端开发 JavaScript Python
flask 项目目录结构
flask 项目目录结构
163 0
|
存储 前端开发 NoSQL
项目阶段之flask(三)
项目阶段之flask(三)
|
3月前
|
Linux Python
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
|
4月前
|
安全 前端开发 API
震惊!掌握Django/Flask后,我竟然轻松征服了所有Web项目难题!
【7月更文挑战第15天】Python Web开发中,Django以其全面功能见长,如ORM、模板引擎,助你驾驭复杂需求;Flask则以轻量灵活取胜,适合快速迭代。两者结合使用,无论是数据库操作、用户认证还是API开发,都能让你应对Web挑战游刃有余。掌握这两者,Web项目难题变得易如反掌!
75 10
|
5月前
|
数据处理 Python
Flask 项目工程目录层级划分
本文介绍了如何将 Flask 项目工程目录层级按照主题分类划分,主要包括模型层、视图层、表单层、模板文件和静态文件。通过合理地组织项目文件,可以提高项目的可读性、可维护性和可扩展性。
85 5
|
6月前
|
前端开发 JavaScript 数据库
Flask狼书笔记 | 09_图片社交网站 - 大型项目的架构与需求(2)
9.8 收藏图片 前面已经学习过如何使用关联表来表示多对多关系,缺点是只能表示关系,不能存储数据(如我还想记录下收藏图片的时间戳)。这种情况下,我们可以使用关联模型来表示多对多关系。 在关联模型中,我们将Photo模型与User模型的多对多关系,分离成了User模型和Collect模型的一对多关系,和Photo模型与Collect模型的一对多关系。
140 0
|
5月前
|
前端开发 索引 Python
【已解决】Flask项目报错TypeError: tuple indices must be integers or slices, not str
【已解决】Flask项目报错TypeError: tuple indices must be integers or slices, not str
|
6月前
|
开发者 索引 Python
Flask环境搭建与项目初始化
【4月更文挑战第15天】本文指导如何搭建Flask开发环境并初始化项目。首先确保安装Python,然后通过pip安装Flask。创建名为`myflaskapp`的项目目录,包含`app.py`入口文件。在`app.py`中初始化Flask应用,定义路由和视图函数。运行`python app.py`启动开发服务器,访问`http://127.0.0.1:5000/`查看结果。完成基本设置后,可按需求扩展应用功能。