我遇到 了几种有关如何在Flask-SQLAlchemy中使用香草SQLAlchemy模型的方法。
使用从BaseFlask-SQLAlchemy继承的模型就像一种魅力。
Base
但是我真的很喜欢那种方便的东西…
Job.query.all() # Does not work db.session.query(Job).all() # Works
因此,我开始着手对此进行研究,并编写了一些代码,但是我受困于此,需要一些帮助才能使它变得更加整洁。
以下块是一个通用定义,不能从任何一个继承。它是从Flask-SQLAlchemy和Vanilla SQLAlchemy导入的,并且应该在某些时候使用。
class VanillaMachine(): __tablename__ = 'machine' id = Column(Integer, primary_key=True) name = Column(String(100)) status = Column(Integer)
并且有一个工厂接受db.Model或Base返回Machine正确的父对象:
db.Model
Machine
class MachineFactory: def __init__(self, *args, **kwargs): pass def __new__(cls, *args, **kwargs): return type('Machine',(object, VanillaMachine, args[0]), VanillaMachine.__dict__.copy())
我很确定该代码有些问题,但是我不确定在哪里。
如果我像这样使用
db = SQLAlchemy() from sqlalchemy.ext.declarative import declarative_base Base = declarative_base()# Machine1 = MachineFactory(db.Model) Machine2 = MachineFactory(Base)
有错误信息
sqlalchemy.exc.ArgumentError: Column object 'id' already assigned to Table 'machine'
可以帮助我以一种不错的,可靠的方式弄清楚这一点吗?
我知道您可以只使用一个函数,将父级作为参数传递给它,VanillaMachine并使用一些if语句,但这太简单了,对吧?:)
VanillaMachine
if
编辑:
我遇到的其他方法是
使用Flask上下文使用Flask-SQLAlchemy模型
with app.app_context(): pass
or
app.app_context().push()
但这对我来说太集中在Flask上,并且不允许清楚地分离模型,使它们独立并适应上下文。
db = SQLAlchemy(app, model_class=Base)
我发现了一个很好的解决方案,它受SQLAlchemy文档中提到的Factory模式和 声明性Mixins的启发。
对于复杂的多级继承方案,需要使用另一种方法@declared_attr.cascading。
@declared_attr.cascading
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy import Column, Integer, String from sqlalchemy import MetaData from sqlalchemy.ext.declarative import declarative_base from flask_sqlalchemy import SQLAlchemy SQLALCHEMY_DATABASE_URI = 'sqlite:///' + '/tmp/test_app.db' engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True) # for vanilla Base = declarative_base() # for Flask (import from app once initialized) db = SQLAlchemy() class MachineMixin: __tablename__ = 'machine' id = Column(Integer, primary_key=True) name = Column(String(100)) status = Column(Integer) class ModelFactory: @staticmethod def create(which_model, which_parent): if which_parent == 'flask_sqlalchemy': parent = db.Model elif which_parent == 'pure_sqlalchemy': parent = Base # now use type() to interit, fill __dict__ and assign a name obj = type(which_model.__name__ + '_' + which_parent, (which_model, parent), {}) return obj test_scenario = 'pure_sqlalchemy' # 'flask_sqlalchemy' Machine = ModelFactory.create(MachineMixin, test_scenario) if test_scenario == 'flask_sqlalchemy': db.metadata.drop_all(bind=engine) db.metadata.create_all(bind=engine) elif test_scenario == 'pure_sqlalchemy': Base.metadata.drop_all(bind=engine) Base.metadata.create_all(bind=engine) Session = sessionmaker(bind=engine) session = Session() session.add(Machine(name='Bob', status=1)) session.commit()