在外部worker中使用sqlalchemy declarative

时间:2014-02-03 21:16:17

标签: heroku sqlalchemy flask flask-sqlalchemy ironworker

我有一个使用Flask和sqlalchemy在python中编写的Web应用程序。这个应用程序在Heroku上运行,作为一个工作者,我使用了ironworker扩展,我在 models 模块中定义了所有模型,如下所示:

from app import db

class Player(db.Model):
    __tablename__ = 'players'
    id = db.Column(db.Integer, primary_key=True)
    ....
    type = db.Column(db.String(50))

    def __init__(self, ....):
        ....

    __mapper_args__ = {
        'polymorphic_identity':'player',
        'polymorphic_on':type
    }

class Outfielder(Player):
    __tablename__ = 'outfielders'
    id = db.Column(db.Integer, db.ForeignKey('players.id'), primary_key=True)

    __mapper_args__ = {
        'polymorphic_identity':'outfielder'
    }

class Goalkeeper(Player):
    __tablename__ = 'goalkeepers'
    id = db.Column(db.Integer, db.ForeignKey('players.id'), primary_key=True)
    __mapper_args__ = {
        'polymorphic_identity':'goalkeeper'
    }

(注意这是如何从app导入db的) 我可以通过实例化模型在我的应用程序中创建这些模型的实例,如下所示:

db = SQLAlchemy(app)

gk = models.Goalkeeper('John', 'Snow', 1, 1, 3456, 67, 55, 187)
of = models.Outfielder('Gary', 'Lineker', 1, 1, 3999, 77, 78, 176)

db.session.add(gk)
db.session.add(of)
db.session.commit()

现在,我想要做的是能够在我的外部工作者上创建这些模型的实例。唯一阻止我这样做的是对我的app模块的依赖。我不觉得这种依赖是合理的,并且想要找到一种更好的设计方法,能够简单地将我的模型模块导出到worker和init sqlalchemy实例,然后创建我的模型实例并将它们保存到数据库中。我可以在应用程序本身中这样做。

请注意,我已经可以从这样的工作人员访问我的数据库了:

db = create_engine(db_url)
metadata = MetaData(db)

print "connection to the database established"

players = Table('players', metadata, autoload=True)
s = players.select()

我只是想找一个更好的方法来反映我的模特结构。具体来说,我正在考虑我的模型发生变化的情况,我将不得不分别维护两端的代码。如果我设法重用模型并在两端使用声明,那么工人方面就不会有任何维护。

1 个答案:

答案 0 :(得分:4)

db.Model是一个SQLAlchemy declarative_base(),所以你可以像使用普通的SQLAlchemy一样使用你的模型。

此示例有效(YourModel是Flask-SQLAlchemy模型):

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

import settings
from models import YourModel

engine = create_engine(settings.SQLALCHEMY_DATABASE_URI)
Session = sessionmaker(bind=engine)    
session = Session()

# do something with your session
session.query(YourModel).first()

您必须将dbapp分开,这样您就可以使用app导入它而不会触发db.init_app创建。

当然你应该小心。如果您动态加载设置,可能会使用import settings而不是current_app.config从错误的地方加载设置,但看起来您已经让您的工作人员加入,所以这对您来说不是问题。

另一个选择是创建另一个Flask应用程序而不是您的大型Web应用程序。

来自Flask-SQLAlchemy文档(http://pythonhosted.org/Flask-SQLAlchemy/api.html#flask.ext.sqlalchemy.SQLAlchemy):

  

您仍然可以直接使用sqlalchemy和sqlalchemy.orm,但请注意   Flask-SQLAlchemy自定义只能通过   此SQLAlchemy类的实例。查询类默认为BaseQuery   对于db.Query,db.Model.query_class和默认的query_class   db.relationship和db.backref。如果你通过这些接口使用   sqlalchemy和sqlalchemy.orm直接,默认查询类将   是sqlalchemy的。

编辑:将sqlalchemy会话与flask-sqlalchemy模型混合时要记住的另一件事是,flask-sqlalchemy会话对象实际上是一个子类,添加了_model_changes字典。根据{{​​3}},如果您不添加_model_changes字段,则无法提交会话:

def create_session(config):
    engine = create_engine(config['DATABASE_URI'])
    Session = sessionmaker(bind=engine)
    session = Session()
    session._model_changes = {}
    return session