我正在尝试在我的数据库(postgresql)中的两个表之间建立一对一的关系。我在python中使用SQLAlchemy。所以,我使用了文档本身给出的一个例子。 one-to-one relationship
from sqlalchemy import Column, ForeignKey, Integer, String, Date, Float
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child = relationship("Child", uselist=False, back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent", back_populates="child"
engine = create_engine('postgresql+psycopg2://testdb:hello@localhost/fullstack')
Base.metadata.create_all(engine)
这会创建两个表parent和child。 现在我在父表和子表中插入值
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from test_databasesetup import Base, Parent, Child
engine = create_engine('postgresql+psycopg2://testdb:hello@localhost/fullstack')
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
parent = Parent()
session.add(parent)
session.commit() // insert in 'parent' table with id=1
// insert into child
child = Child(parent_id=1)
session.add(child)
session.commit()
child = Child(parent_id=1)
session.add(child)
session.commit()
使用相同的parent_id再次插入child应该抛出错误但是插入了记录。
id | parent_id
----+-----------
1 | 1
2 | 1
这里应该做什么,这样我只能插入一个与父ID对应的子节点。我不希望孩子拥有相同的parent_id。
感谢。
答案 0 :(得分:2)
问题是您是直接指定字段parent_id
。在这种情况下,sqlalchemy
无法将关系验证为one-to-one
。相反,请使用以下关系:
# add new parent to the database
parent = Parent()
session.add(parent)
session.commit()
# insert new child for this parent
child = Child(parent=parent) # @note: this is the code change. \
# Here we refer to parent, not parent_id field
session.add(child)
session.commit()
# insert another child for the same parent:
# this will assign this new child to the parent, and will
# *remove* previous child from this parent
child = Child(parent=parent)
session.add(child)
session.commit()
另一个副作用是代码更清晰。还有一个事实是sqlalchemy
可以找出外键本身,而且你不需要知道对象的id
:
parent = Parent()
child = Child(parent=parent)
# it is enough to add only one related object, and the other (Child) will be added to session automatically
session.add(parent)
# we can commit only now, when we finished working on all the objects in the current session/transaction
session.commit()
此外,您可以向Child.parent_id
字段添加唯一约束作为额外的数据库级别检查,这会在您的情况下引发错误:
parent_id = Column(Integer, ForeignKey('parent.id'), unique=True)