首页 > 解决方案 > SQLAlchemy:如何访问两个表中的关系

问题描述

我正在开发一个系统来跟踪当前的设备固件并将其与推荐的版本进行比较。模型和代码已简化如下。我有三个模型VersionFirmwareHistoryVersionRecommendation

VersionRecommendation表可以列出多个Versions作为首选,因为我们支持多个主要分支。现在我正在尝试交叉引用FirmwareHistoryVersionRecommendation查看设备是否正在运行推荐的版本或更高版本。

以下查询为我提供了运行推荐版本的所有设备的列表。

session.query(FirmwareHistory, func.max(FirmwareHistory.date), VersionRecommendation)\
            .filter(VersionRecommendation.preferred == True)\
            .group_by(FirmwareHistory.device_id)\
            .filter(FirmwareHistory.version_id == VersionRecommendation.version_id)
            .all()

但是我也想访问Version属性FirmwareHistoryVersionRecommendation检查major属性。并且只返回版本major相同的结果。

基本上:给我一个结果,其中FirmwareHistoryVersionRecommendation两者都相同Version.major

我试过了:

session().query(FirmwareHistory, func.max(FirmwareHistory.date), VersionRecommendation)\
    .filter(VersionRecommendation.preferred == True)\
    .group_by(FirmwareHistory.device_id)\
    .filter(VersionRecommendation.version.major == FirmwareHistory.version.major)\
    .all()

但这给了我一个属性错误:AttributeError:与 SoftwareRevision.version 关联的“InstrumentedAttribute”对象和“Comparator”对象都没有属性“major”

我尝试加入这两个版本,但 SQLAlchemy 因列名而感到困惑:

session.query(FirmwareHistory, func.max(FirmwareHistory.date), VersionRecommendation)\
    .filter(VersionRecommendation.preferred == True)\
    .group_by(FirmwareHistory.device_id)\
    .join(FirmwareHistory.version)\
    .join(VersionRecommendation.version)\
    .filter(FirmwareHistory.version_id == VersionRecommendation.version_id)
    .all()

有没有办法做到这一点?

标签: pythonsqlalchemyflask-sqlalchemy

解决方案


不要通过FirmwareHistoryor引用版本VersionRecommendation,而只是将其作为模型访问:

session.query(FirmwareHistory, func.max(FirmwareHistory.date), VersionRecommendation)\
    .select_from(FirmwareHistory)\
    .join(Version)\
    .join(VersionRecommendation)\
    .filter(VersionRecommendation.preferred == True)\
    .group_by(FirmwareHistory.device_id)\
    .all()

或者,如果您真的想避免额外的连接,您可以明确指定连接条件。不过,我不会这样做,因为 PostgreSQL 通常足够聪明,可以将其优化掉。

session.query(FirmwareHistory, func.max(FirmwareHistory.date), VersionRecommendation)\
    .select_from(FirmwareHistory)\
    .join(VersionRecommendation, FirmwareHistory.version_id == VersionRecommendation.version_id)\
    .filter(VersionRecommendation.preferred == True)\
    .group_by(FirmwareHistory.device_id)\
    .all()

推荐阅读