Flask 本身不内置 ORM,不内置迁移系统,也不内置用户模型和后台。
这不是缺点,而是它的设计边界。
官方教程给出的纯 Flask 做法,是自己写数据库访问模块,再通过 g 和 CLI 命令组织:
import click
import sqlite3
from flask import current_app, g
def get_db():
if "db" not in g:
g.db = sqlite3.connect(current_app.config["DATABASE"])
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop("db", None)
if db is not None:
db.close()
def init_db():
db = get_db()
with current_app.open_resource("schema.sql") as f:
db.executescript(f.read().decode("utf-8"))
@click.command("init-db")
def init_db_command():
init_db()
click.echo("initialized the database")
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)然后你就可以:
flask --app riderhub init-db这说明 Flask 的思路是:
核心框架只负责把街区调度好,具体后勤仓库和工兵系统,由你自己选。
如果你接扩展,官方又推荐另一条重要模式:
扩展对象先创建,但别在导入时就和 app 绑死,要用 init_app。
以常见 ORM 扩展模式为例:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///riderhub.db"
db.init_app(app)
return app而不是这样:
db = SQLAlchemy(app) # 不推荐在大型项目里这么早硬绑定这个模式的好处是:
- 测试更好做
- 多 app 实例更好做
- 结构更清楚
- 扩展对象不携带某个具体 app 的粘连状态