python - Sqlalchemy 真的有一对一的关系吗

标签 python sqlalchemy one-to-one

我有以下语义。警报可以有一个状态更改,而且只有一个。 状态更改只能有一个警报。状态变化可能有一个原因,也可能有多个状态变化 我尝试了以下模式

class Alert(BaseDb):
    __tablename__ = 'alerts'
    __table_args__ = (
        PrimaryKeyConstraint('id', name='pk_alerts'),
    )

    id = Column(Integer)
    alert_text = Column(Text)

class AlertStateChange(BaseDb):
    __tablename__ = 'alert_state_change'
    __table_args__ = (
        PrimaryKeyConstraint('id', name='pk_alert_state_change'),
        ForeignKeyConstraint(
            ['reason_id'],
            ['reasons.id'],
            name='fk_alert_status_change_reason_id__reasons'
        ),

        ForeignKeyConstraint(
            ['alert_id'],
            ['alerts.id'],
            name='fk_alert_status_change_alert_id__alert'
        ),


    )

    id = Column(Integer)
    reason_id = Column(Integer)
    alert_id = Column(Integer)
    reason = relationship('Reason', backref='status')
    alert = relationship('Alert',
                         backref=backref('status', uselist=False))
    status = Column(Text)

但 sqlalchemy 允许我为相同的警报(相同的 alert_id)添加到 AlertStateChange 对象。它通常使用新的 id 提交。在数据库中为同一警报放置两个 AlertStatusChange 对象后尝试以下操作

alert.status

给我以下警告

SAWarning: Multiple rows returned with uselist=False for lazily-loaded attribute 'Alert.status' % self.parent_property)

并且返回的对象是添加的第一个 AlertStateChange 对象。第二个在数据库中但被忽略了。不应该提出异常(exception)吗?这不是真正的 OneToOne 关系。我应该将 alert_id 添加为主键还是唯一值,对吗?

最佳答案

执行这些操作:

  • 在关系上设置uselist=False
  • 在子unique=True中设置引用列
  • 您还可以为 child 设置nullable=False
  • 并且您可以添加到父自定义 __init__ 以实现严格的一对一

现在它可以工作了。

class Parent(Base):
    __tablename__ = 'parents'

    id = Column(Integer, primary_key=True)
    Child = relationship("Child", uselist=False, backref="Parent")

    def __init__(self,**kwargs):
        if 'Child' not in kwargs:
            raise RuntimeError('Need value')
        ...

class Child(Base):
    __tablename__ = 'childs'

    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parents.id'), unique=True)    

Base.metadata.create_all(engine)
session = Session(bind=engine)

ch1 = Child(Parent=Parent())
session.add(ch1)

p1 = Parent(Child=Child())
session.add(p1)

session.commit()

for row in session.query(Parent):
    print row.Child.id
for row in session.query(Child):
    print row.Parent.id

关于python - Sqlalchemy 真的有一对一的关系吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42726070/

相关文章:

java - Hibernate OneToOne BiDirectional Optional Relationship : Works when inserted without optional object, 在使用新的可选对象更新时中断

hibernate - @OneToOne和@JoinColumn,自动删除空实体,可行吗?

Python 套接字绑定(bind)到 3 个网络接口(interface)中的 2 个

python - 使用 python re 查找所有模式

python - 如何按元素将 6 个元素的数组与 12 个元素的数组相乘,并重复较小的数组?

python - 如何从 SQLAlchemy 模型中确定子对象的类型?

python - 如何删除json文件python中的元素

python - 使用 Sqlalchemy 计算列中的项目数

python - 如何应用 SqlAlchemy `BinaryExpression` 作为列表上的过滤器?

java - 如何使用 @OneToOne 关系同时持久化两个实体?