如何在不完全传递 db 对象的情况下将 Flask 模型从 app.py 中拆分出来?

How do I split Flask models out of app.py without passing db object all over?

我想使用 Flask-Migrate 并且正在查看他们的示例:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

db = SQLAlchemy(app)
migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))

if __name__ == '__main__':
    manager.run()

这作为一个简单的游戏示例效果很好,但我有不止一个模型,我不想在这个脚本和定义我的应用程序代码的脚本中定义模型。因此,我想将它们拉到一个模型文件中,我可以在两者之间共享。

我试图通过将 User class 放入 models.py 然后从那里导入用户来做到这一点。不幸的是,这会引发 NameError: name 'db' is not defined.

我的问题是:

这是一个想法。您可以创建一个包 model,在其中将 class 定义为单独的 .py 文件。例如,user.py 包含 User class.

__init__.py 文件中您可以定义 db 变量。您还可以包含 from user import User 语句,以便可以直接在包外访问 User 对象。例如,您可以使用 import model 在程序的其他地方导入 model 包,然后使用 model.User 直接使用 User class.

要在 user.py 中直接使用 db 变量,请使用 from ..model import db 导入 __init__.py 文件中定义的 db 变量。

将这么小的应用程序划分为模块是很棘手的,因为您会发现很多情况下您创建的两个模块需要相互导入,从而产生循环依赖。

我建议您了解如何使用应用工厂函数和所有扩展的延迟初始化来正确构建更大的应用程序。执行此操作的示例应用程序是我书中的 Flasky 应用程序。

综上所述,可以将应用程序分成两部分,您只需要注意放置导入语句的位置即可。在下面的示例中,我决定将 db 实例和 User 模型的创建移动到 models.py 文件中。

这是主要应用程序的模块:

from flask import Flask
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

from models import db  # <-- this needs to be placed after app is created
migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manager.run()

这里是 models.py:

from __main__ import app
from flask.ext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))

这里主模块会创建app,然后才会导入models.py。当 models.py 尝试从主模块导入 app 时,它已经被创建。如果您将 from models import db 移动到文件的顶部以及其他导入,则此代码会中断。

你的回答对我很有帮助。我终于掌握了相当繁琐的 python 导入规则。在这里,我尝试以一种更清晰的方式来说明该模式(我所说的“更清晰”是指不会因其他问题而复杂化,例如迁移问题)。这是将应用程序划分为一个主模块和一个仅声明数据库模型的辅助模块的简单而常见的情况。

主要内容:

from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__) # this is a key point

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///clientes.sqlite3'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 
app.config['SECRET_KEY'] = "random string"

from fasiDB import db, Corr, Cliente, Producto # db and models

# here come the various routes which access db

型号:

from __main__ import app
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy(app) # the argument "app" comes from main

class Corr(db.Model):
    id = db.Column('corr_id', db.Integer, primary_key=True)
    nf = db.Column(db.Integer)

...

class Cliente(db.Model):
   id = db.Column('cliente_id', db.Integer, primary_key = True)
   nombre = db.Column(db.String(64), unique=True)
   rSocial = db.Column(db.String(64), unique=True)
   ruc = db.Column(db.String(27), unique=True)
   dir = db.Column(db.String(100))

...