#sqlalchemy
Вопрос:
Я хотел бы вставить дочерний объект (см. Определения классов ниже), который связан с родительским объектом, который может существовать или не существовать в базе данных, а затем получить сгенерированный первичный ключ для дочернего объекта. Я пробовал использовать Session.add
и то, и Session.merge
другое, но у меня возникли проблемы с обоими.
- Использование
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» уже существует.
- Использование
Session.merge
работает, но я не могу получить сгенерированный идентификатор для нового ребенка:
# 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")
Ответ №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"))
Комментарии:
1. Спасибо! Мне было интересно , будет ли способ избежать ручной проверки наличия объекта в базе
get
данных, например, если это будет частью магии, которую SQLAlchemy выполняет с объектами отношений. Но я думаю, что нет…?