python - 不存在具有给定属性的相关模型时的 SQLAlchemy 查询模型
问题描述
我有三个模型(请注意,这是在 Flask-SQLAlchemy 中完成的,但如果你只能为 vanilla SQLAlchemy 写一个答案,那对我来说很好。)为了清楚起见,删除了不相关的字段。
class KPI(db.Model):
__tablename__ = 'kpis'
id = db.Column(db.Integer, primary_key=True)
identifier = db.Column(db.String(length=50))
class Report(db.Model):
__tablename__ = 'reports'
id = db.Column(db.Integer, primary_key=True)
class ReportKPI(db.Model):
report_id = db.Column(db.Integer, db.ForeignKey('reports.id'), primary_key=True)
kpi_id = db.Column(db.Integer, db.ForeignKey('kpis.id'), primary_key=True)
report = db.relationship('Report', backref=db.backref('values'))
kpi = db.relationship('KPI')
我的目标是找到所有Report
不测量特定值的对象KPI
(即,没有ReportKPI
对象的KPI
关系已identifier
设置为特定值)。
我的一个尝试看起来像
Report.query \
.join(ReportKPI) \
.join(KPI) \
.filter(KPI.identifier != 'reflection')
但这会返回更多Report
实际存在的对象(我想我会得到一个ReportKPI
除了KPI
“反射”之外的任何东西。)
我想用 SQLAlchemy 实现的目标真的可行吗?如果是这样,神奇的词是什么(请似乎不起作用……)
解决方案
EXISTS 子查询表达式非常适合您的目标。编写此类查询的一种速记方法是:
Report.query.\
filter(db.not_(Report.values.any(
ReportKPI.kpi.has(identifier='reflection'))))
但这会产生 2 个嵌套的 EXISTS 表达式,尽管 EXISTS 中的连接也可以:
Report.query.\
filter(db.not_(
ReportKPI.query.
filter_by(report_id=Report.id).
join(KPI).
filter_by(identifier='reflection').
exists()))
最后,带有 IS NULL 的 LEFT JOIN 也是一种选择:
Report.query.\
outerjoin(db.join(ReportKPI, KPI),
db.and_(ReportKPI.report_id == Report.id,
KPI.identifier == 'reflection')).\
filter(KPI.id.is_(None))