首页 > 解决方案 > 当您使用不同的值更新模型的关系及其对应的列时,您如何控制提交时使用哪个值?

问题描述

所以我在我的模型中声明了一个克隆方法,如下所示:

def clone(self):
    valid_cols = [key for key, val in vars(type(self)).items() if isinstance(val, InstrumentedAttribute) and key not in self.__table__.primary_key.columns]
    return type(self)(**{key: getattr(self, key) for key in valid_cols})

这使得克隆记录然后更新它们的属性变得又好又容易。

不过有问题。每当我更新已复制其关联关系的字段时,我都会遇到不希望的行为。

例如,采取:

class Parent(Base):
    __tablename__ = "parent"
    id = Column(Integer, primary_key=True)


class Child(Base):
    __tablename__ = "child"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey(Parent.id))

    parent = relationship(Parent, backref=Backref("children", uselist=True, cascade="all"))

    def clone(self):
        from sqlalchemy.orm.attributes import InstrumentedAttribute
        valid_cols = [key for key, val in vars(type(self)).items() if isinstance(val, InstrumentedAttribute) and key not in self.__table__.primary_key.columns]
        return type(self)(**{key: getattr(self, key) for key in valid_cols})


metadata.create_all()


parent1 = Parent()
parent2 = Parent()
child1 = Child(parent=parent1)

s.add_all([parent1, parent2, child1])
s.commit()

child2 = child1.clone()
child2.parent_id = parent2.id

child2.parent_id  # 2

s.add(child2)
s.commit()

child2.parent_id  # 1
child2.parent is parent1  # True

因此,很明显,child2 的父母应该是 parent2,而不是 parent1。但是 parent1 在 clone 方法期间直接设置在 child2 的 'Child.parent' 关系上,所以即使 child2 的 'Child.parent_id' 列后来设置为 parent2 的 id,orm 并不关心并在提交时丢弃了该更新。

我的问题是,当关系属性和列属性之间存在分歧时,有没有办法让 orm 将最后修改的属性作为绝对真理?

我可以避免在 clone 方法中设置关系属性,但我不想这样做,因为在更复杂的情况下,访问旧对象的关系非常有用,而且我也发现在我的用例中能够直接设置列属性,而不是设置它们的关系属性。

在向数据库提交任何内容之前,我还想对克隆对象进行任何必要的更新。

基本上,有没有简单的银弹?任何方式我都可以修改克隆方法,以便在保持其他所有内容不变的情况下,在示例代码的结尾处 child2 的 parent 将是 parent2 而不是 parent1?

提前非常感谢。

标签: pythonpython-3.xsqlalchemy

解决方案


推荐阅读