我正在尝试以编程方式构建一个搜索查询,为此,我要加入一个表。
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
已经加入,如果是的话就跳过它,那太酷了。我有一些更复杂的查询构建,它们确实会从中受益。
如果对于我错过的搜索有一个完全不同的查询构建策略,那也很棒。或者,如果我两次加入表,上面的代码就可以了,那也是很好的信息。任何帮助都非常感谢!
可以通过检查查询的
_from_obj
属性来访问 SQLAlchemy 查询对象中连接的表。此属性包含构成查询 FROM 子句的一系列表。
以下是检查
Tag
表是否已连接到的
search
函数的方法:
from sqlalchemy import inspect
def search(title_arg, desc_arg):
query = User.query
if title_arg:
# 检查 Tag 是否已连接
if not any(isinstance(table, Tag.__table__) for table in inspect(query).fromclause._from_obj):
query = query.join(Tag)
query = query.filter(Tag.title.contains(title_arg))
if desc_arg:
# 检查 Tag 是否已连接
if not any(isinstance(table, Tag.__table__) for table in inspect(query).fromclause._from_obj):
query = query.join(Tag)
query = query.filter(Tag.description.contains(desc_arg))
return query
此代码使用
inspect(query).fromclause._from_obj
获取连接表的列表,并检查
Tag.__table__
是否存在于列表中。如果该表不存在,则会执行连接。
但是,在 SQLAlchemy 中,多次连接同一个表通常是不必要的,甚至可能导致意外行为。 SQLAlchemy 足够智能,可以处理多个过滤器,即使它们应用于通过单个连接连接的同一表。
因此,可以简化
search
函数,而无需检查表是否已连接:
def search(title_arg, desc_arg):
query = User.query
if title_arg:
query = query.join(Tag).filter(Tag.title.contains(title_arg))
if desc_arg:
query = query.join(Tag).filter(Tag.description.contains(desc_arg))
return query
此代码仅在需要时连接
Tag
表,并且无论
title_arg
和
desc_arg
的值如何,它都能正常工作。SQLAlchemy 将优化查询,并且不会执行不必要的连接。