温馨提示:本文翻译自stackoverflow.com,查看原文请点击:python - How to create a child SQL-Alchemy instance from a parent instance?
class flask python flask-sqlalchemy

python - 如何从父实例创建子SQL-Alchemy实例?

发布于 2020-03-29 21:31:17

我有两个模型,SignalTrade我的Trade对象从继承其属性Signal,因为几乎所有属性都是相同的,但是有些关键函数和属性使它与众不同。我正在写一个Signal名为的方法as_trade(),我想Trade实例上的所有数据/属性创建一个实例,Signal以便将其保存到数据库中。我正在使用Deepcopy-一直在起作用,但是实际上我认为这不是正确/最佳的方法。是否有尝试/测试过的方式来执行这样的动作?

class Signal(db.Model):
    __tablename__ = 'signal'
    id = db.Column(db.Integer, primary_key=True)
    class_type = db.Column(db.String())

    __mapper_args__ = {
        'polymorphic_identity': 'signal',
        'polymorphic_on': class_type,
    }

    # MAIN FIELDS
    type = db.Column(db.String(20))

    def as_trade(self):
       signal_dict = self.__dict__
       for key in ['id', 'user_id', '_sa_instance_state', 'class_type']:
           signal_dict.pop(key)
       trade = Trade(**signal_dict)
       return trade

    ...

class Trade(Signal):
    __tablename__ = 'trade'
    id = db.Column(db.Integer, db.ForeignKey('signal.id'), primary_key=True)

    __mapper_args__ = {
        'polymorphic_identity': 'trade',
    }
    ....

我应该补充一点,我要问的问题是,当as_trade()被调用时,它会引发关键错误。如果我self.id在PDB中调用,则会得到一个值(1)。但是,如果我打电话,self.__dict__我只会得到一个InstanceState,没有任何属性。因此,它抛出一个keyError。但是有时,通过调用self_dict和self。dict,而在PDB中,我可以使字典实际出现并具有值-这是我不了解的部分。撇开它,程序在此失败,因为给定self会抛出keyError。dict只给出InstanceState对象。但是在PDB中闲逛并自我称呼。dict向前迈出了一步,因为该词典显示了所有必需的属性...,从而允许for循环完成。

{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000002E694983B88>
}

更新:之所以时髦的原因是因为_sa_instance_state从字典中弹出时,状态正在起作用。如果我留_sa_instance_state在字典对象中并将其传递给Trade(),则会收到错误消息TypeError: '_sa_instance_state' is an invalid keyword argument for Trade

查看更多

提问者
phil0s0pher
被浏览
282
SuperShoot 2020-01-31 19:25

如果Signal类和Trade类都共享相同的数据库列,并且它们唯一的区别在于类上定义的方法,则使用单个表继承模型是有意义的。

如果不定义表名,Flask-SQLAlchemy会神奇地定义表名,则需要显式设置__tablename__子类属性,None以表示您打算使用单个表结构。

然后,如果目标是将Signal对象的列的值复制到新的Trade对象,则可以遍历的列Signal.__table__以从中获取列的值Signal并将其写入的新实例Trade

循环看起来像这样:

signal = db.session.query(Signal).one()
new_trade = Trade()
for col in Signal.__table__.c:
    if col.key not in ("id", "type"):
        setattr(new_trade, col.key, getattr(signal, col.key))

这是一个完整的工作示例:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///test.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)


class Signal(db.Model):
    __tablename__ = "signal"
    id = db.Column(db.Integer, primary_key=True)

    # MAIN FIELDS
    type = db.Column(db.String(20))
    col1 = db.Column(db.Integer)
    col2 = db.Column(db.Integer)

    __mapper_args__ = {"polymorphic_on": "type", "polymorphic_identity": "signal"}


class Trade(Signal):

    __tablename__ = None

    __mapper_args__ = {"polymorphic_identity": "trade"}


if __name__ == "__main__":
    db.drop_all()
    db.create_all()
    db.session.add(Signal(col1=1, col2=2))
    db.session.commit()
    signal = db.session.query(Signal).one()
    new_trade = Trade()
    for col in Signal.__table__.c:
        if col.key not in ("id", "type"):
            setattr(new_trade, col.key, getattr(signal, col.key))
    db.session.add(new_trade)
    db.session.commit()
    db.session.expire_all()
    trade = db.session.query(Trade).first()
    print(trade.col1, trade.col2)