Flask项目的目录结构

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的默认模式。

但有的时候,可能需要以上两种模式混合使用。例如,有的数据库模型可能在多个蓝本中都会用到,不好区分他们究竟属于哪个蓝本。

参考链接

觉得有用可以请作者喝杯咖啡呀~
0%