Sqlalchemy 用其外键值替换关系

问题描述 投票:0回答:1

考虑以下架构

class Parent(Base):
    __tablename__ = "parents"
    id = Column(Integer, primary_key=True)
    ... # A lot of other attributes and relationships

class Child(Base):
    __tablename__ = "childs"
    id = Column(Integer, primary_key=True)
    parent_id  = Column(Integer, ForeignKey("parents.id"), nullable=False)
    parent = relationship(Parent)
    ... # A lot of other attributes and relationships

(我使用的是Sqlalchemy 1.4)

假设我有一个来自上一个会话的

Parent
对象

session.expire_on_commit=False
parent = session.query(Parent).filter(Parent.id == 1)

我尝试根据它插入一个新的

Child
实例:

new_child = Child(parent=parent)
session.add(new_child)
session.commit()

这可以工作,但它不是线程安全的,就像我试图针对同一父级并行创建很多

Child
实例一样,我收到与此类似的错误。

sqlalchemy.exc.InvalidRequestError: Object '<Parent at 0x7fdcf96bdc10>' is already attached to session '51' (this is '52')

(错误要么来自父类,要么来自与之相关的另一个类)。

我也不能只用

Child
键实例化
parent_id
,因为应用程序的很多行为都是基于父级的属性及其关系。

天真地,我以为我可以做类似的事情

# Run the application, and when needing to insert the Child, with a new session do:
child.parent_id = child.parent.id
child.parent = None

当我跑步时,虽然表示看起来不错

<Child id=None, parent_id=1, ...>
,但事件

session.add(child)
session.commit()

我收到错误 ```{'S': 'ERROR', 'V': 'ERROR', 'C': '23502', 'M': '关系“childs”的“parent_id”列中的空值违反非空约束...'`

确实,在提交期间的某个地方,我的

parent_id
已被替换,我的
child
现在看起来像这样
<Child id=None, parent_id=None, ...>

我已经尝试过

session.merge
中描述的方法这个答案,但由于我的现实世界示例处理更多的关系和属性,它似乎试图创建重复的值。

我在寻找答案:

  • 需要最少的代码更改。如果有一个简单的方法调用允许我将
    parent
    关系设置为
    None
    ,同时允许在会话提交期间保留
    parent_id
    ,这将是完美的解决方案
  • 允许发挥更复杂的关系模式(例如,有一个
    GrandChild
    类,与
    child
    有关系,并且将与
    child
    实例同时插入
python-3.x sqlalchemy
1个回答
0
投票

我目前能想到的唯一解决方案是创建一个新的

Child
实例而不指定

new_child_to_insert = Child(parent_id=new_child.parent_id, ...) # Use a lot of other attributes
session.add(new_child_to_insert)

但是,这个解决方案对于我的实际使用来说非常麻烦,因为我有很多不同的 在

Child
类中管理的属性和关系

© www.soinside.com 2019 - 2024. All rights reserved.