解决方案是为那些与组织没有直接关系的类使用composite "secondary" join。例如网站:
class Site(Base):
organization = relationship(
"Organization",
secondary="join(Operation, Region).join(Area)",
uselist=False,
innerjoin=True,
viewonly=True)
而区域应该只使用表操作作为辅助:
class Region(Base):
organization = relationship(
"Organization",
secondary="operation",
uselist=False,
innerjoin=True,
viewonly=True)
以上是仅显示关系配置的简化版本。一个具体的例子如下:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine("sqlite://")
Base = declarative_base()
Base.metadata.bind = engine
Session = sessionmaker()
class Organization(Base):
__tablename__ = 'organization'
id = Column(Integer, primary_key=True)
class Operation(Base):
__tablename__ = 'operation'
id = Column(Integer, primary_key=True)
organization_id = Column(ForeignKey('organization.id'))
organization = relationship("Organization")
class Region(Base):
__tablename__ = 'region'
id = Column(Integer, primary_key=True)
operation_id = Column(ForeignKey('operation.id'))
organization = relationship(
"Organization",
secondary="operation",
uselist=False, innerjoin=True, viewonly=True)
operation = relationship("Operation")
class Area(Base):
__tablename__ = 'area'
id = Column(Integer, primary_key=True)
region_id = Column(ForeignKey('region.id'))
organization = relationship(
"Organization",
secondary="join(Operation, Region)",
uselist=False, innerjoin=True, viewonly=True)
region = relationship("Region")
class Site(Base):
__tablename__ = 'site'
id = Column(Integer, primary_key=True)
area_id = Column(ForeignKey('area.id'))
organization = relationship(
"Organization",
secondary="join(Operation, Region).join(Area)",
uselist=False, innerjoin=True, viewonly=True)
area = relationship("Area")
Base.metadata.create_all()
session = Session()
session.add(Site(area=Area(region=Region(operation=Operation(organization=Organization())))))
session.commit()
site = session.query(Site).options(joinedload(Site.organization)).first()
print(site)
print(site.organization)
print(site.area.organization)
print(site.area.region.organization)
print(site.area.region.operation.organization)