Flask 是一个非常灵活的 Web 开发框架,因而其目录结构可以有多种形式。
单独实例化扩展对象
在相关文件中单独实例化扩展对象,而不是将扩展对象放入__init__.py
中。这是 Flask 官方文档推荐的方式。
引用原作者的一句话:
Don’t backward import from root __init__.py
.
示例
举个例子,我们使用 Flask-SQLAlchemy 扩展,则在 models.py
中创建 SQLAlchemy
对象。
yourapplication/__init__.py
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| from flask import Flask
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
|
yourapplication/models.py
:
1
2
3
4
5
6
| from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
pass
|
原因
为了避免一些情况下的循环导入问题。
假如我们在 __init__.py
中实例化 SQLAlchemy
对象,那么在 models.py
需要从 __init__.py
中导入该对象以便创建数据库模型。但若另一扩展使用某个模型进行初始化,则需要在 __init__.py
中导入模型。这就造成了 models.py
和 __init__.py
之间的循环导入。
yourapplication/__init__.py
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from yourapplication.models import User
db = SQLAlchemy()
ext = AnotherExtension(User)
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
|
yourapplication/models.py
:
1
2
3
4
| from yourapplication import db
class User(db.Model):
pass
|
基于功能的组织结构
所有内容按照其功能(模型、路由、模版、API 等等)分别存放在不同目录中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| project
├── __init__.py
├── models
│ ├── __init__.py
│ ├── posts.py
│ └── users.py
├── routes
│ ├── __init__.py
│ ├── auth.py
│ ├── dashboard.py
│ └── home.py
├── services
│ ├── __init__.py
│ ├── google.py
│ └── mail.py
└── templates
├── home.html
└── login.html
|
在 project/__init__.py
文件中编写 create_app
工厂函数,并执行所有的 init_app
方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
| ## project/__init__.py
from flask import Flask
def create_app():
from . import models, routes, services
app = Flask(__name__)
models.init_app(app)
routes.init_app(app)
services.init_app(app)
return app
|
这里原作者的一个小技巧是,在每个目录的 __init__.py
文件中,都定义一个 init_app
方法,在其中再调用 Flask 扩展的 init_app
方法或注册蓝本。
1
2
3
4
5
6
7
8
9
10
11
12
13
| # project/models/__init__.py
from .base import db
def init_app(app):
db.init_app(app)
# project/routes/__init__.py
from .users import user_bp
from .posts import posts_bp
def init_app(app):
app.register_blueprint(user_bp)
app.register_blueprint(posts_bp)
|
基于 app 的组织结构
基于 app 的内容,或者说基于蓝本来组织目录结构,每个蓝本为一个目录,每个目录下有自己单独的路由、模型、模版等。
1
2
3
4
5
6
7
8
9
10
11
12
13
| project
├── __init__.py
├── auth
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ └── templates
├── blog
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ └── templates
└── db.py
|
这是另一个比较有名的组织方式,《Flask Web 开发:基于 Python 的 Web 应用开发实战》书中即使用了该种方式,这也是 Django 的默认模式。
但有的时候,可能需要以上两种模式混合使用。例如,有的数据库模型可能在多个蓝本中都会用到,不好区分他们究竟属于哪个蓝本。
参考链接