【问题标题】:Inserting a child object with a parent when the parent already exists with SQLAlchemy当父对象已经存在时,使用 SQLAlchemy 插入带有父对象的子对象
【发布时间】:2021-09-19 16:19:11
【问题描述】:

我想插入一个子对象(参见下面的类定义),它与数据库中可能已经存在或不存在的父对象有关系,然后获取为子对象生成的主键。我尝试同时使用Session.addSession.merge,但我都遇到了问题。

  1. 当父对象已存在于表中时,使用Session.add 不起作用。例如,以下失败:
# Create a parent with id 1
parent = Parent(id = 1)
with Session(engine) as session:
    session.add(parent)
    session.commit()

...

# Later, add a child whose parent is the one with id 1. 
# I know the parent id and don't need to fetch it from
# the database, thus I'm directly creating the parent object. 
parent = Parent(id = 1)
child = Child(parent = parent)
with Session(engine) as session:
    session.add(child)
    session.commit()
    print("child.id = " + str(child.id))

它产生:

IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "parent_pkey"
DETAIL:  Key (id)=(1) already exists.

SQLAlchemy 正在尝试再次添加父项,但抱怨主键“1”已经存在。

  1. 使用 Session.merge 有效,但我无法为新孩子获取生成的 id:
# The Parent with id = 1 now exists in the parent table

# Add the child with the parent using merge
parent = Parent(id = 1)
child = Child(parent = parent)
with Session(engine) as session:
    session.merge(child)
    session.commit()
    print("child.id = " + str(child.id))

这显示child.id = None

我可能没有走正确的路,我非常感谢一些方向。

以下是示例类定义:

    class Parent(Base):
        __tablename__ = 'parent'

        id = Column(Integer, primary_key = True)

        children = relationship("Child", back_populates = "parent")

    class Child(Base):
        __tablename__ = 'children'

        id = Column(Integer, primary_key = True)
        parent_id = Column(Integer, ForeignKey("parent.id"), nullable = False)

        parent = relationship("Parent", back_populates = "children")


【问题讨论】:

    标签: sqlalchemy


    【解决方案1】:

    您应该检查它是否已经存在,而不是随意创建parent = Parent(id = 1)

    # retrieve parent from database …
    parent1 = session.get(Parent, 1)
    if not parent1:
        # … and create if not found
        session.add(parent1 := Parent(id=1, name="Homer"))
    

    【讨论】:

    • 谢谢!我想知道是否有办法避免使用get 手动检查对象是否存在于数据库中,例如,这是否是 SQLAlchemy 对关系对象所做的魔术的一部分。但我猜不是……?
    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多