在 SQLAlchemy 中查找祖先的关系

Posted

技术标签:

【中文标题】在 SQLAlchemy 中查找祖先的关系【英文标题】:Relationship to find ancestor in SQLAlchemy 【发布时间】:2017-11-14 13:46:43 【问题描述】:

我有一棵看起来像这样的一对多关系树:

组织->运营->区域->区域->站点

organization 是***祖先。 site 有一个area_idarea 有一个region_id,依此类推。

对于组织下的每个实体,我希望能够通过site.organizationarea.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 映射的小例子

Python 学习笔记 - SQLAlchemy(下)

Python 学习笔记 - sqlAlchemy(初稿)

flask mysql sqlalchemy教程

sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres

“SQLAlchemy”类中未解析的属性“Column”