【问题标题】:SQLAlchemy one-to-one relationship creates multiple rowsSQLAlchemy 一对一关系创建多行
【发布时间】:2016-03-31 05:41:05
【问题描述】:

我正在尝试在我的数据库 (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 的子项应该会引发错误,但记录已插入。

id | parent_id 
----+-----------
  1 |         1
  2 |         1

这里应该做些什么,这样我就只能插入一个与父ID对应的孩子。我不希望孩子拥有相同的 parent_id。

谢谢。

【问题讨论】:

    标签: python sql postgresql sqlalchemy


    【解决方案1】:

    问题是您直接指定字段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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 2016-06-15
      • 2021-08-31
      • 1970-01-01
      • 2020-11-01
      • 1970-01-01
      • 2020-05-10
      相关资源
      最近更新 更多