如何在Flask+SQLAlchemy中正确配置House与Member的一对多ORM映射
问题解答
误解纠正
你对mapper的properties配置规则的理解存在错误:SQLAlchemy执行映射时,会自动为被映射类动态注入properties中定义的属性,不需要提前在类中声明对应属性,所以即便Member类没有预先定义house属性,该配置也是合法的。
一对多关系正确配置步骤
你的业务场景确实不需要中间关联表,仅需在member侧加外键即可,完整的修正方案如下:
1. 修正原生Python类的笔误
你提供的House、Member类存在多处命名不一致的问题,会直接导致运行报错,先修正:
# model.py 修正后代码 import typing class House: def __init__(self, members: typing.Set['Member'] = None) -> None: # 原代码错误引用了不存在的patients变量 if not members: # 原代码属性名是member,和后续映射的members不一致,统一改为复数形式更合理 self.members = set() else: self.members = set(members) def add_member(self, person: 'Member'): # 原代码错误调用了self.patients self.members.add(person) def remove_member(self, member: 'Member'): self.members.remove(member) class Member: def __init__(self, first_name: str, email: str, phone: str, age: int, gender: str, last_name=None) -> None: self.first_name = first_name self.last_name = last_name self.email = email self.phone = phone self.age = age self.gender = gender def __hash__(self) -> int: return hash(self.email) def __eq__(self, other): # 原代码错误判断了不存在的Patient类 if isinstance(other, Member): return self.email == other.email return NotImplemented
2. 修正表定义,删除中间表、新增外键
# orm.py 表定义修正后代码 from sqlalchemy import Table, Column, Integer, String, ForeignKey, MetaData metadata = MetaData() house = Table( 'house', metadata, Column('id', Integer, primary_key=True, autoincrement=True) ) member = Table( # 你的表名是patient,注意和外键引用时的表名保持一致 'patient', metadata, Column('id', Integer, primary_key=True, autoincrement=True), Column('first_name', String(255)), Column('last_name', String(255)), Column('email', String(255)), Column('phone', String(255)), Column('age', Integer), Column('gender', String(255)), # 新增关联house的外键 Column('house_id', Integer, ForeignKey('house.id')) ) # 删除原来的member_allocation中间表,一对多场景不需要
3. 修正映射配置
def start_mappers(): # 先映射Member类,不需要提前配置house属性 member_mapper = mapper(model.Member, member) # 映射House类,在properties中配置一对多关系 house_mapper = mapper( model.House, house, properties={ 'members': relationship( member_mapper, collection_class=set, # backref会自动为Member类注入house属性,不需要单独在Member的mapper里配置 backref=backref('house') ), })
验证使用
配置完成后你可以直接通过以下方式操作关联关系:
# 新建House和Member house1 = House() member1 = Member(first_name="张", email="zh@test.com", phone="13xxxx", age=25, gender="男") # 关联关系,两种方式都生效 house1.add_member(member1) # 或者 member1.house = house1
内容的提问来源于stack exchange,提问作者Joaquim A Pinto
相关产品推荐
相关产品推荐

