【问题标题】:How do I split Flask models out of app.py without passing db object all over?如何在不传递 db 对象的情况下将 Flask 模型从 app.py 中拆分出来?
【发布时间】:2015-12-15 05:41:23
【问题描述】:

我想使用 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 类放入models.py,然后从那里导入用户。不幸的是,这会引发NameError: name 'db' is not defined。

我的问题是:

  • 我是否需要在我的models.py 中使用db = SQLAlchemy(app),如果需要,我的迁移脚本和flask 应用程序本身都可以使用它吗?
  • 如果我不能(或不应该)把它放在models.py 中,我如何在他们自己的文件中使用我的模型而不传递db?

【问题讨论】:

标签: python flask flask-migrate


【解决方案1】:

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

我建议您了解如何正确构建更大的应用程序,使用应用程序工厂函数和延迟初始化所有扩展。我书中提到的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 移动到文件顶部,其他导入则此代码会中断。

【讨论】:

  • 我理解您的示例,但如果我想要将models.py 拆分为不同的.pys 怎么办?例如 User.py、Foo.py、Bar.py。我正在努力寻找一种方法来做到这一点。
  • @VitorHugo 你可以创建一个models 包,在包的__init__.py 文件中创建db 实例,然后为每个模型添加一个模块,所有这些模块都将db 实例导入为from . import db.
  • 在调用db.create_all()之前必须导入所有模型。
  • 是的,您还可以在导入db 的同一位置导入User。
  • 很高兴看到带有models 包的工作解决方案的代码。
【解决方案2】:

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

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

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

【讨论】:

  • 这是否意味着我需要传递app(来自db = SQLAlchemy(app))而不是db?
  • 好吧,在这种情况下,您可以在__init__.py 中添加app 和db
  • @aliasm2k model 模块的重点是将模型与应用程序分开。将它们都放在包 init 中并没有比将它们放在单个模块中更松散的耦合。
【解决方案3】:

你的回答对我很有帮助。我终于掌握了相当繁琐的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))

...

【讨论】:

    猜你喜欢
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    相关资源
    最近更新 更多