在 SQLAlchemy 中查找祖先的关系
Posted
技术标签:
【中文标题】在 SQLAlchemy 中查找祖先的关系【英文标题】:Relationship to find ancestor in SQLAlchemy 【发布时间】:2017-11-14 13:46:43 【问题描述】:我有一棵看起来像这样的一对多关系树:
组织->运营->区域->区域->站点
organization
是***祖先。 site
有一个area_id
,area
有一个region_id
,依此类推。
对于组织下的每个实体,我希望能够通过site.organization
、area.organization
等关系快速访问组织祖先。
每个实体上的relationship
会是什么样子才能完成这项工作?
【问题讨论】:
【参考方案1】:解决方案是为那些与组织没有直接关系的类使用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)
【讨论】:
这似乎不起作用,并且链接的文档令人困惑......显示的示例在每个子实体上都有一个***实体的外键。就我而言,每个实体中的直接父级只有一个外键。 我能说什么,它对我有用。如果您在问题本身中提供实际的示例代码,那么生成开箱即用的答案会更容易。如果没有您的代码,此答案中的示例必然需要进行一些微调。大体思路是:创建一个派生表/复合表作为辅助,主要是需要的连接。由于您所追求的是多对一,但需要辅助,因此您必须通过uselist=False
才能产生标量关系。如果您的外键不可为空,请同时传递 innerjoin=True
。以上是关于在 SQLAlchemy 中查找祖先的关系的主要内容,如果未能解决你的问题,请参考以下文章
sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres