如何用SQLAlchemy通过关联模型实现同一模型的一对一关系
解决SQLAlchemy同一模型一对一关联的问题
修正后的代码实现
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, create_engine from sqlalchemy.orm import relationship, Session from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Person(Base): __tablename__ = 'persons' id = Column(Integer, primary_key=True) # 分别定义作为关系双方的反向关联,uselist=False确保一对一 relationship_as_person1 = relationship( 'PersonRelationship', foreign_keys='PersonRelationship.person1_id', uselist=False, back_populates='person1' ) relationship_as_person2 = relationship( 'PersonRelationship', foreign_keys='PersonRelationship.person2_id', uselist=False, back_populates='person2' ) # 快捷属性,直接获取关联的伴侣 @property def partner(self): if self.relationship_as_person1: return self.relationship_as_person1.person2 elif self.relationship_as_person2: return self.relationship_as_person2.person1 return None class PersonRelationship(Base): __tablename__ = 'person_relationships' id = Column(Integer, primary_key=True) person1_id = Column(Integer, ForeignKey('persons.id')) person2_id = Column(Integer, ForeignKey('persons.id')) relationship_type = Column(String(50)) # 存储关系类型,比如"伴侣"、"好友"等 # 添加唯一约束,确保一个人只能出现在一个一对一关系中 __table_args__ = ( UniqueConstraint('person1_id', name='unique_person1'), UniqueConstraint('person2_id', name='unique_person2'), ) # 关联到Person模型的对应反向关系 person1 = relationship( 'Person', foreign_keys=[person1_id], back_populates='relationship_as_person1' ) person2 = relationship( 'Person', foreign_keys=[person2_id], back_populates='relationship_as_person2' ) # 初始化数据库 engine = create_engine('sqlite:///the_database.db') session = Session(engine) Base.metadata.create_all(engine) # 创建实例并关联 p1 = Person() p2 = Person() partner_relation = PersonRelationship(person1=p1, person2=p2, relationship_type='伴侣') session.add_all([p1, p2, partner_relation]) session.commit() # 测试获取关联对象 print(p1.partner.id) # 输出p2的id print(p2.partner.id) # 输出p1的id
关键修正点
- 拆分反向关联:原代码用单个
partner_relationship同时映射两个外键的反向关系,SQLAlchemy无法区分来源,因此拆分为relationship_as_person1和relationship_as_person2,分别对应关联表中的两个外键。 - 强制一对一:通过
uselist=False将关系设置为一对一,而非默认的一对多。 - 唯一性约束:在关联表中给
person1_id和person2_id分别添加唯一约束,确保一个用户只能存在于一个一对一关系中。 - 自动处理外键:创建关联对象时无需手动传入
person1_id和person2_id,SQLAlchemy会在提交会话时自动填充生成的主键值。 - 快捷属性封装:通过
partner属性简化伴侣对象的获取,无需区分当前用户是关系中的哪一方。
内容的提问来源于stack exchange,提问作者Touten
相关产品推荐
相关产品推荐

