如何修正我在香草SQLAlchemy和FlaskSQLAlchemy中使用相同模型的方法?

2024-09-30 16:22:09 发布

您现在位置:Python中文网/ 问答频道 /正文

Icameacrossseveral关于如何在SQLAlchemy中使用vanilla SQLAlchemy模型的方法

将继承自Base的模型与炼金术结合使用就像一种魅力

但我真的很喜欢那种方便的东西

Job.query.all() # Does not work
db.session.query(Job).all() # Works

所以我开始做这件事,并整理了一些代码,但我被卡住了,需要一些帮助才能把这件事弄清楚

下面的块是一个通用定义,它不从任何一个继承。 它是进口的,应该在某个时候从烧瓶炼金术和香草炼金术中使用

class VanillaMachine():

    __tablename__ = 'machine'

    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    status = Column(Integer)

还有一个工厂,它接受db.ModelBase并返回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语句,但这太简单了,不是吗?:)

编辑:

我遇到的其他方法有

  1. 使用烧瓶上下文使用烧瓶SQLAlchemy模型

    with app.app_context():
        pass
    
    or 
    
    app.app_context().push()
    

但这对我来说过于集中于Flask,不允许清晰地分离模型,使它们独立并适应上下文

  1. db = SQLAlchemy(app, model_class=Base)提供替代基类,请参见here。这可能对我有用,但到目前为止我没有对此进行评估

Tags: 方法模型appdbbase烧瓶sqlalchemyargs
1条回答
网友
1楼 · 发布于 2024-09-30 16:22:09

我从Factory patternDeclarative Mixins如SQLAlchemy文档中所述

对于复杂的多级继承场景,需要使用@declared_attr.cascading使用different approach


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()

相关问题 更多 >