我正在尝试以编程方式构建搜索查询,为此,我正在加入一个表。
class User(db.Model):
id = db.Column(db.Integer(), primary_key=True)
class Tag(db.Model):
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id'))
title = db.Column(db.String(128))
description = db.Column(db.String(128))
这是一个人为的例子 - 我希望它有意义。
假设我的搜索功能类似于:
def search(title_arg, desc_arg):
query = User.query
if title_arg:
query = query.join(Tag)
query = query.filter(Tag.title.contains(title_arg))
if desc_arg:
query = query.join(Tag)
query = query.filter(Tag.description.contains(desc_arg))
return query
以前,我已经跟踪了列表中已加入的表格,如果表格在列表中,假设它已经加入,只需添加过滤器。
如果我可以查看查询对象,看看Tag
已经加入,那就太酷了,如果是的话就跳过它。我有一些更复杂的查询构建,可以从中受益。
如果对于我错过的搜索构建查询的策略完全不同,那也会很棒。或者,如果上面的代码没有问题,如果我两次加入表格,这也是很好的信息。任何帮助都非常值得赞赏!!!
答案 0 :(得分:10)
您可以在query._join_entities
joined_tables = [mapper.class_ for mapper in query._join_entities]
答案 1 :(得分:5)
从 SQLAlchemy 1.4 开始,包括 _join_entities
在内的早期提出的解决方案不再有效。
我试图在 SQLAlchemy 1.4 中解决这个问题,但有一个警告:
from sqlalchemy.sql import visitors
from contextlib import suppress
def _has_entity(self, model) -> bool:
for visitor in visitors.iterate(self.statement):
# Checking for `.join(Parent.child)` clauses
if visitor.__visit_name__ == 'binary':
for vis in visitors.iterate(visitor):
# Visitor might not have table attribute
with suppress(AttributeError):
# Verify if already present based on table name
if model.__table__.fullname == vis.table.fullname:
return True
# Checking for `.join(Child)` clauses
if visitor.__visit_name__ == 'table':
# Visitor might be of ColumnCollection or so,
# which cannot be compared to model
with suppress(TypeError):
if model == visitor.entity_namespace:
return True
return False
def unique_join(self, model, *args, **kwargs):
"""Join if given model not yet in query"""
if not self._has_entity(model):
self = self.join(model, *args, **kwargs)
return self
Query._has_entity = _has_entity
Query.unique_join = unique_join
对于 SQLAlchemy 1.3 及之前版本,@mtoloo 和 @r-m-n 给出了完美的答案,为了完整起见,我将它们包括在内。
在项目初始化的某些地方,向 sqlalchemy.orm.Query 对象添加一个 unique_join 方法,如下所示:
def unique_join(self, *props, **kwargs):
if props[0] in [c.entity for c in self._join_entities]:
return self
return self.join(*props, **kwargs)
现在使用 query.unique_join 而不是 query.join:
Query.unique_join = unique_join
答案 2 :(得分:2)
根据r-m-n答案:
在初始化项目的某些位置,向unique_join
对象添加sqlalchemy.orm.Query
方法,如下所示:
def unique_join(self, *props, **kwargs):
if props[0] in [c.entity for c in self._join_entities]:
return self
return self.join(*props, **kwargs)
Query.unique_join = unique_join
现在使用query.unique_join
代替query.join
:
query = query.unique_join(Tag)