SqlAlchemy 2.0 中文文档(三十)(4)https://developer.aliyun.com/article/1562438
特殊查询技术
本节将描述一些特定查询情况下的技术。
使用 IN 表达式
SQLAlchemy 中的ColumnOperators.in_()
方法在历史上基于传递给方法的项目列表呈现一个可变的绑定参数集。对于已烘焙的查询,这不起作用,因为该列表的长度可能在不同的调用中发生变化。为了解决这个问题,bindparam.expanding
参数支持一个延迟呈现的 IN 表达式,在烘焙查询内安全地进行缓存。实际元素列表在语句执行时呈现,而不是在语句编译时:
bakery = baked.bakery() baked_query = bakery(lambda session: session.query(User)) baked_query += lambda q: q.filter(User.name.in_(bindparam("username", expanding=True))) result = baked_query.with_session(session).params(username=["ed", "fred"]).all()
请参阅下文
bindparam.expanding
ColumnOperators.in_()
使用子查询
当使用Query
对象时,通常需要一个Query
对象用于在另一个查询中生成子查询。在Query
目前处于烘焙形式的情况下,可以使用一个临时方法来检索Query
对象,使用BakedQuery.to_query()
方法。此方法传递给生成烘焙查询特定步骤的 lambda 可调用参数的Session
或Query
:
bakery = baked.bakery() # a baked query that will end up being used as a subquery my_subq = bakery(lambda s: s.query(User.id)) my_subq += lambda q: q.filter(User.id == Address.user_id) # select a correlated subquery in the top columns list, # we have the "session" argument, pass that my_q = bakery(lambda s: s.query(Address.id, my_subq.to_query(s).as_scalar())) # use a correlated subquery in some of the criteria, we have # the "query" argument, pass that. my_q += lambda q: q.filter(my_subq.to_query(q).exists())
版本 1.3 中的新功能。
使用 before_compile 事件
从 SQLAlchemy 1.3.11 开始,针对特定Query
使用QueryEvents.before_compile()
事件将禁止烘焙查询系统缓存查询,如果事件挂钩返回一个与传入的不同的新Query
对象。这样,QueryEvents.before_compile()
挂钩可以在每次使用特定Query
时被调用,以适应每次以不同方式修改查询的挂钩。要允许QueryEvents.before_compile()
修改sqlalchemy.orm.Query()
对象,但仍然允许结果被缓存,可以注册传递bake_ok=True
标志的事件:
@event.listens_for(Query, "before_compile", retval=True, bake_ok=True) def my_event(query): for desc in query.column_descriptions: if desc["type"] is User: entity = desc["entity"] query = query.filter(entity.deleted == False) return query
上述策略适用于每次都以完全相同方式修改给定Query
的事件,不依赖于特定参数或外部状态的更改。
版本 1.3.11 中的新功能:- 在QueryEvents.before_compile()
事件中添加了“bake_ok”标志,并且如果此标志未设置,则不允许通过“baked”扩展进行缓存以发生对返回新Query
对象的事件处理程序。
禁用全局会话烘焙查询
标志Session.enable_baked_queries
可以设置为 False,导致所有烘焙查询在针对该Session
使用时不使用缓存:
session = Session(engine, enable_baked_queries=False)
像所有会话标志一样,它也被工厂对象(如sessionmaker
)和方法(如sessionmaker.configure()
)接受。
此标志的直接理由是,一个应用程序如果出现问题,可能是由于用户定义的烘焙查询或其他烘焙查询问题导致的缓存键冲突,可以关闭该行为,以确定或排除烘焙查询作为问题原因。
版本 1.2 中的新功能。
惰性加载集成
从版本 1.4 开始更改:从 SQLAlchemy 1.4 开始,“烘焙查询”系统不再是关系加载系统的一部分。而是改用本地缓存系统。
API 文档
对象名称 | 描述 |
BakedQuery | 用于构建Query 对象的构建器对象。 |
bakery | 构建一个新的烘焙坊。 |
Bakery | 返回一个BakedQuery 的可调用对象。 |
function sqlalchemy.ext.baked.bakery(size=200, _size_alert=None)
构建一个新的烘焙坊。
返回:
一个Bakery
的实例。
class sqlalchemy.ext.baked.BakedQuery
成员
add_criteria(), bakery(), for_session(), spoil(), to_query(), with_criteria()
用于构建Query
对象的构建器对象。
method add_criteria(fn, *args)
向这个BakedQuery
添加一个条件函数。
这相当于使用+=
运算符就地修改BakedQuery
。
classmethod bakery(size=200, _size_alert=None)
构建一个新的烘焙坊。
返回:
一个Bakery
的实例。
method for_session(session)
为这个BakedQuery
返回一个Result
对象。
这相当于将BakedQuery
作��Python 可调用对象调用,例如result = my_baked_query(session)
。
method spoil(full=False)
取消在此BakedQuery
对象上发生的任何查询缓存。
BakedQuery
可以继续正常使用,但是附加的创建函数不会被缓存;它们将在每次调用时被调用。
这是为了支持在构建烘焙查询的特定步骤中,某些使查询无法缓存的情况,例如依赖于某些不可缓存值的变体。
参数:
full – 如果为 False,则仅在破坏步骤之后添加到此BakedQuery
对象的函数将不被缓存;直到此时为止的BakedQuery
的状态将从缓存中拉取。如果为 True,则每次完全从头构建整个Query
对象,每次调用都会调用所有创建函数。
method to_query(query_or_session)
返回作为子查询使用的Query
对象。
此方法应在用于生成封闭的BakedQuery
步骤的 lambda 可调用对象内部使用。参数通常应该是传递给 lambda 的Query
对象:
sub_bq = self.bakery(lambda s: s.query(User.name)) sub_bq += lambda q: q.filter( User.id == Address.user_id).correlate(Address) main_bq = self.bakery(lambda s: s.query(Address)) main_bq += lambda q: q.filter( sub_bq.to_query(q).exists())
在子查询用于第一个针对Session
的可调用对象时,也接受Session
:
sub_bq = self.bakery(lambda s: s.query(User.name)) sub_bq += lambda q: q.filter( User.id == Address.user_id).correlate(Address) main_bq = self.bakery( lambda s: s.query( Address.id, sub_bq.to_query(q).scalar_subquery()) )
参数:
query_or_session –
一个Query
对象或一个类Session
对象,假设它在封闭的BakedQuery
可调用对象的上下文中。
版本 1.3 中的新功能。
method with_criteria(fn, *args)
向从此克隆的BakedQuery
添加一个条件函数。
这相当于使用+
运算符产生一个具有修改的新BakedQuery
。
class sqlalchemy.ext.baked.Bakery
返回一个返回BakedQuery
的可调用对象。
此对象由类方法BakedQuery.bakery()
返回。它存在为了便于检查“缓存”。
版本 1.2 中的新功能。
class sqlalchemy.ext.baked.Result
对一个Session
发起一个BakedQuery
的调用。
Result
对象是实际创建或从缓存中检索的针对目标Session
的Query
对象,并且然后为结果调用。
method all()
返回所有行。
等效于Query.all()
。
method count()
返回‘count’。
等效于Query.count()
。
请注意,这使用子查询确保准确计算,而不管原始语句的结构如何。
method first()
返回第一行。
等效于Query.first()
。
method get(ident)
根据标识检索对象。
等效于Query.get()
。
method one()
返回确切的一个结果或引发异常。
等效于Query.one()
。
method one_or_none()
返回一个或零个结果,或者对于多行引发异常。
等效于Query.one_or_none()
。
method params(*args, **kw)
指定要替换为字符串 SQL 语句的参数。
method scalar()
返回第一个结果的第一个元素,如果没有行,则返回 None。如果返回多行,则引发 MultipleResultsFound 异常。
等效于Query.scalar()
。
method with_post_criteria(fn)
添加一个将在缓存后应用的条件函数。
这将添加一个函数,该函数将针对从缓存中检索的Query
对象运行。目前仅包括Query.params()
和Query.execution_options()
方法。
警告
Result.with_post_criteria()
函数应用于Query
对象之后查询的 SQL 语句对象已从缓存中检索。只应使用Query.params()
和Query.execution_options()
方法。
在版本 1.2 中新增。
概要
使用烘焙系统的方法是首先生成所谓的“烘焙坊”,该坊代表一系列特定的查询对象的存储:
from sqlalchemy.ext import baked bakery = baked.bakery()
上述“面包店”将在默认为 200 个元素的 LRU 缓存中存储缓存数据,需要注意的是,ORM 查询通常会包含一个为调用的 ORM 查询条目,以及每个数据库方言的 SQL 字符串的条目。
面包店允许我们通过指定其构造方式为一系列 Python 可调用对象来构建一个Query
对象,这些对象通常是 lambda 表达式。为了简洁使用,它重写了+=
运算符,使得典型的查询构建看起来像下面这样:
from sqlalchemy import bindparam def search_for_user(session, username, email=None): baked_query = bakery(lambda session: session.query(User)) baked_query += lambda q: q.filter(User.name == bindparam("username")) baked_query += lambda q: q.order_by(User.id) if email: baked_query += lambda q: q.filter(User.email == bindparam("email")) result = baked_query(session).params(username=username, email=email).all() return result
以下是关于上述代码的一些观察:
baked_query
对象是BakedQuery
的一个实例。这个对象本质上是一个真正的 ormQuery
对象的“构造器”,但它本身并不是真正的Query
对象。- 实际的
Query
对象根本没有构建,直到函数的最后一刻调用Result.all()
时。 - 添加到
baked_query
对象的步骤都表示为 Python 函数,通常是 lambda 函数。给bakery()
函数的第一个 lambda 函数以Session
作为其参数。其余的 lambda 函数每个都以Query
作为其参数。 - 在上述代码中,即使我们的应用程序可能多次调用
search_for_user()
,即使在每次调用中我们都会构建一个全新的BakedQuery
对象,所有的 lambda 函数只会被调用一次。只要此查询被缓存在面包店中,每个 lambda 函数永远不会再次被调用。 - 缓存是通过存储lambda 对象本身的引用来实现的,以形成一个缓存键;也就是说,Python 解释器将这些函数分配给 Python 标识符,这决定了如何在后续运行中识别查询。对于那些指定了
email
参数的search_for_user()
调用,可调用对象lambda q: q.filter(User.email == bindparam('email'))
将成为检索到的缓存键的一部分;当email
为None
时,此可调用对象不会成为缓存键的一部分。 - 因为 lambda 函数只被调用一次,所以至关重要的是在 lambda 函数内部不引用可能在调用之间更改的变量;相反,假设这些是要绑定到 SQL 字符串中的值,我们使用
bindparam()
来构造命名参数,在稍后使用Result.params()
应用其实际值。
性能
烘焙查询可能看起来有点奇怪,有点笨拙,有点啰嗦。然而,在应用程序中调用多次的查询中,Python 性能的节约非常显著。在 Performance 中演示的示例套件 short_selects
对比了每个仅返回一行的查询,例如以下常规查询:
session = Session(bind=engine) for id_ in random.sample(ids, n): session.query(Customer).filter(Customer.id == id_).one()
与等效的“烘焙”查询相比:
bakery = baked.bakery() s = Session(bind=engine) for id_ in random.sample(ids, n): q = bakery(lambda s: s.query(Customer)) q += lambda q: q.filter(Customer.id == bindparam("id")) q(s).params(id=id_).one()
对于对每个块进行 10000 次调用的 Python 函数调用次数的差异为:
test_baked_query : test a baked query of the full entity. (10000 iterations); total fn calls 1951294 test_orm_query : test a straight ORM query of the full entity. (10000 iterations); total fn calls 7900535
在一台性能强大的笔记本电脑上,这在秒数上表现如下:
test_baked_query : test a baked query of the full entity. (10000 iterations); total time 2.174126 sec test_orm_query : test a straight ORM query of the full entity. (10000 iterations); total time 7.958516 sec
请注意,这个测试非常有意地包含了只返回一行的查询。对于返回许多行的查询,烘焙查询的性能优势将逐渐减少,与获取行所花费的时间成比例。必须牢记的是,烘焙查询功能仅适用于构建查询本身,而不适用于获取结果。使用烘焙功能绝不是使应用程序更快的保证;它只是一个可能有用的功能,适用于那些已经被测量为受到这种特定形式的开销影响的应用程序。
理念
上面的“lambda”方法是更传统的“参数化”方法的超集。假设我们希望构建一个简单的系统,在这个系统中我们只需构建一个Query
,然后将其存储在字典中以便重复使用。现在,我们可以通过构建查询,然后通过调用 my_cached_query = query.with_session(None)
来移除其Session
来实现这一点:
my_simple_cache = {} def lookup(session, id_argument): if "my_key" not in my_simple_cache: query = session.query(Model).filter(Model.id == bindparam("id")) my_simple_cache["my_key"] = query.with_session(None) else: query = my_simple_cache["my_key"].with_session(session) return query.params(id=id_argument).all()
上述方法只能带来非常微小的性能提升。通过重用Query
,我们可以节省在session.query(Model)
构造函数内部的 Python 工作以及调用filter(Model.id == bindparam('id'))
时所需的工作,这将为我们跳过 Core 表达式的构建以及将其发送到Query.filter()
。然而,该方法仍然在每次调用Query.all()
时重新生成完整的Select
对象,并且每次还会将这个全新的Select
对象发送到字符串编译步骤中,对于像上面这样的简单情况,这可能占据了大约 70% 的开销。
为了减少额外的开销,我们需要一些更专门的逻辑,一种记忆构建选择对象和构建 SQL 的方法。在维基中的BakedQuery部分有一个例子,这是该功能的前身,但在那个系统中,我们没有缓存查询的构建。为了消除所有开销,我们需要缓存查询的构建以及 SQL 编译。假设我们按照这种方式调整了配方,并制作了一个.bake()
方法,用于预先编译查询的 SQL,生成一个可以以最小开销调用的新对象。我们的例子变成了:
my_simple_cache = {} def lookup(session, id_argument): if "my_key" not in my_simple_cache: query = session.query(Model).filter(Model.id == bindparam("id")) my_simple_cache["my_key"] = query.with_session(None).bake() else: query = my_simple_cache["my_key"].with_session(session) return query.params(id=id_argument).all()
上面,我们已经解决了性能问题,但我们仍然需要处理这个字符串缓存键。
我们可以使用“面包房”方法来重新构建上述方法,使其看起来不像“构建 lambda”方法那样不寻常,而更像是对简单“重用查询”的简单改进:
bakery = baked.bakery() def lookup(session, id_argument): def create_model_query(session): return session.query(Model).filter(Model.id == bindparam("id")) parameterized_query = bakery.bake(create_model_query) return parameterized_query(session).params(id=id_argument).all()
上面,我们使用“baked”系统的方式与简单的“缓存查询”系统非常相似。但是,它使用了两行更少的代码,不需要制造一个“my_key”的缓存键,而且还包含了与我们自定义的“bake”函数相同的功能,该函数缓存了查询构造函数,筛选调用,生成Select
对象以及字符串编译步骤的 100% Python 调用工作。
从上面的内容中,如果我们问自己,“如果查找需要根据查询结构做条件决策,会怎样?”,这就是为什么“烘焙”是这样的方式的原因。我们可以从任意数量的函数构建参数化查询,而不是从一个函数构建(这是我们最初认为烘焙可能起作用的方式)。考虑我们的简单示例,如果我们需要在查询中有一个额外的条件子句:
my_simple_cache = {} def lookup(session, id_argument, include_frobnizzle=False): if include_frobnizzle: cache_key = "my_key_with_frobnizzle" else: cache_key = "my_key_without_frobnizzle" if cache_key not in my_simple_cache: query = session.query(Model).filter(Model.id == bindparam("id")) if include_frobnizzle: query = query.filter(Model.frobnizzle == True) my_simple_cache[cache_key] = query.with_session(None).bake() else: query = my_simple_cache[cache_key].with_session(session) return query.params(id=id_argument).all()
我们的“简单”参数化系统现在必须负责生成缓存键,考虑到是否传递了“include_frobnizzle”标志,因为该标志的存在意味着生成的 SQL 将完全不同。很明显,随着查询构建的复杂性增加,缓存这些查询的任务会很快变得繁重。我们可以将上面的示例转换为直接使用“bakery”如下:
bakery = baked.bakery() def lookup(session, id_argument, include_frobnizzle=False): def create_model_query(session): return session.query(Model).filter(Model.id == bindparam("id")) parameterized_query = bakery.bake(create_model_query) if include_frobnizzle: def include_frobnizzle_in_query(query): return query.filter(Model.frobnizzle == True) parameterized_query = parameterized_query.with_criteria( include_frobnizzle_in_query ) return parameterized_query(session).params(id=id_argument).all()
在上面的情况下,我们不仅缓存查询对象,还缓存生成 SQL 所需的所有工作。我们也不再需要处理确保生成准确考虑到我们所做的所有结构修改的缓存键;这现在是自动处理的,而且没有错误的机会。
这段代码示例比简单示例少了几行,消除了处理缓存键的需要,并具有完整的所谓“烘焙”功能的巨大性能优势。但仍然有点冗长!因此,我们将像BakedQuery.add_criteria()
和BakedQuery.with_criteria()
这样的方法缩短为运算符,并鼓励(尽管当然不是必须!)使用简单的 lambda 表达式,只是为了减少冗长:
bakery = baked.bakery() def lookup(session, id_argument, include_frobnizzle=False): parameterized_query = bakery.bake( lambda s: s.query(Model).filter(Model.id == bindparam("id")) ) if include_frobnizzle: parameterized_query += lambda q: q.filter(Model.frobnizzle == True) return parameterized_query(session).params(id=id_argument).all()
在上面的情况下,这种方法更容易实现,并且在代码流程上更类似于非缓存查询函数的代码,因此使得代码更容易移植。
上述描述基本上是到达当前“烘焙”方法的设计过程的总结。从“正常”方法开始,缓存键构建和管理的额外问题,消除所有多余的 Python 执行以及需要处理条件构建的查询都需要解决,最终导致了最终方法。
特殊查询技术
这一部分将描述一些特定查询情况下的技术。
使用 IN 表达式
在 SQLAlchemy 中,ColumnOperators.in_()
方法在历史上基于传递给方法的项目列表渲染一组变量绑定参数。这对于烘焙查询不起作用,因为该列表的长度可能在不同调用时发生变化。为了解决这个问题,bindparam.expanding
参数支持一个延迟渲染的 IN 表达式,可以安全地缓存在烘焙查询内部。实际元素列表在语句执行时渲染,而不是在语句编译时:
bakery = baked.bakery() baked_query = bakery(lambda session: session.query(User)) baked_query += lambda q: q.filter(User.name.in_(bindparam("username", expanding=True))) result = baked_query.with_session(session).params(username=["ed", "fred"]).all()
另请参阅
bindparam.expanding
ColumnOperators.in_()
使用子查询
在使用Query
对象时,通常需要一个Query
对象用于在另一个内部生成子查询。在Query
当前处于烘焙形式的情况下,可以使用一个中间方法来检索Query
对象,使用BakedQuery.to_query()
方法。该方法传递给生成烘焙查询特定步骤的 lambda 可调用参数的Session
或Query
:
bakery = baked.bakery() # a baked query that will end up being used as a subquery my_subq = bakery(lambda s: s.query(User.id)) my_subq += lambda q: q.filter(User.id == Address.user_id) # select a correlated subquery in the top columns list, # we have the "session" argument, pass that my_q = bakery(lambda s: s.query(Address.id, my_subq.to_query(s).as_scalar())) # use a correlated subquery in some of the criteria, we have # the "query" argument, pass that. my_q += lambda q: q.filter(my_subq.to_query(q).exists())
版本 1.3 中新增。
使用 before_compile 事件
自 SQLAlchemy 1.3.11 起,针对特定的 Query
使用 QueryEvents.before_compile()
事件将禁止烘焙查询系统缓存查询,如果事件挂钩返回一个与传入的不同的新 Query
对象。这样,每次使用特定的 Query
都可以调用 QueryEvents.before_compile()
钩子,以适应每次更改查询的钩子。要允许 QueryEvents.before_compile()
修改 sqlalchemy.orm.Query()
对象,但仍然允许结果被缓存,可以注册事件并传递 bake_ok=True
标志:
@event.listens_for(Query, "before_compile", retval=True, bake_ok=True) def my_event(query): for desc in query.column_descriptions: if desc["type"] is User: entity = desc["entity"] query = query.filter(entity.deleted == False) return query
上述策略适用于每次以完全相同方式修改给定的 Query
的事件,不依赖于特定参数或更改的外部状态。
新版本 1.3.11 中添加了 bake_ok
标志到 QueryEvents.before_compile()
事件,并且如果此标志未设置,则不允许为返回新 Query
对象的事件处理程序通过“烘焙”扩展进行缓存。 ### 使用 IN 表达式
SQLAlchemy 中的 ColumnOperators.in_()
方法在历史上根据传递给方法的项目列表呈现一组变量绑定参数。对于烘焙查询,这不起作用,因为该列表的长度可以在不同的调用中改变。为解决此问题,bindparam.expanding
参数支持在烘焙查询中安全缓存的延迟呈现 IN 表达式。实际元素列表在语句执行时呈现,而不是在语句编译时:
bakery = baked.bakery() baked_query = bakery(lambda session: session.query(User)) baked_query += lambda q: q.filter(User.name.in_(bindparam("username", expanding=True))) result = baked_query.with_session(session).params(username=["ed", "fred"]).all()
另请参阅
bindparam.expanding
ColumnOperators.in_()
使用子查询
当使用Query
对象时,通常需要一个Query
对象用于在另一个查询中生成子查询。在当前Query
处于烘焙形式时,可能需要使用一个临时方法来检索Query
对象,该方法使用BakedQuery.to_query()
方法。此方法传递给用于生成烘焙查询特定步骤的 lambda 可调用的Session
或Query
参数:
bakery = baked.bakery() # a baked query that will end up being used as a subquery my_subq = bakery(lambda s: s.query(User.id)) my_subq += lambda q: q.filter(User.id == Address.user_id) # select a correlated subquery in the top columns list, # we have the "session" argument, pass that my_q = bakery(lambda s: s.query(Address.id, my_subq.to_query(s).as_scalar())) # use a correlated subquery in some of the criteria, we have # the "query" argument, pass that. my_q += lambda q: q.filter(my_subq.to_query(q).exists())
新版本 1.3。
使用 before_compile 事件
从 SQLAlchemy 1.3.11 开始,针对特定Query
使用QueryEvents.before_compile()
事件将阻止烘焙查询系统缓存查询,如果事件钩子返回一个与传入的不同的新Query
对象。这是为了每次使用时都可以调用特定QueryEvents.before_compile()
钩子,以适应每次都以不同方式修改查询的钩子。要允许QueryEvents.before_compile()
修改sqlalchemy.orm.Query()
对象,但仍然允许结果被缓存,可以注册事件并传递bake_ok=True
标志:
@event.listens_for(Query, "before_compile", retval=True, bake_ok=True) def my_event(query): for desc in query.column_descriptions: if desc["type"] is User: entity = desc["entity"] query = query.filter(entity.deleted == False) return query
以上策略适用于每次都会以完全相同方式修改给定的Query
的事件,不依赖于特定参数或会发生变化的外部状态。
新版本 1.3.11 中新增:- 在QueryEvents.before_compile()
事件中添加了“bake_ok”标志,并且如果未设置此标志,则禁止通过“baked”扩展对返回新的Query
对象的事件处理程序进行缓存。
禁用全局 Baked 查询
标志Session.enable_baked_queries
可以设置为 False,导致所有烘焙查询在用于该Session
时不使用缓存:
session = Session(engine, enable_baked_queries=False)
与所有会话标志一样,它也被工厂对象如sessionmaker
和方法如sessionmaker.configure()
所接受。
此标志的直接理由是,应用程序可能由于用户定义的烘焙查询或其他烘焙查询问题而看到问题,可以将行为关闭,以识别或排除烘焙查询作为问题的原因。
版本 1.2 中的新功能。
惰性加载集成
从版本 1.4 起更改:自 SQLAlchemy 1.4 起,“烘焙查询”系统不再是关系加载系统的一部分。取而代之的是使用本地缓存系统。
API 文档
对象名称 | 描述 |
BakedQuery | 用于Query 对象的构建器对象。 |
bakery | 构建一个新的面包店。 |
Bakery | 返回一个BakedQuery 的可调用对象。 |
function sqlalchemy.ext.baked.bakery(size=200, _size_alert=None)
构建一个新的面包店。
返回:
一个Bakery
的实例
class sqlalchemy.ext.baked.BakedQuery
成员
add_criteria(), bakery(), for_session(), spoil(), to_query(), with_criteria()
用于Query
对象的构建器对象。
method add_criteria(fn, *args)
为此BakedQuery
添加一个条件函数。
这相当于使用 +=
运算符就地修改BakedQuery
。
classmethod bakery(size=200, _size_alert=None)
构建一个新的面包店。
返回:
一个Bakery
的实例
method for_session(session)
为此BakedQuery
返回一个Result
对象。
这相当于将BakedQuery
作为 Python 可调用对象调用,例如 result = my_baked_query(session)
。
method spoil(full=False)
取消此BakedQuery
对象上将发生的任何查询缓存。
BakedQuery
仍然可以正常使用,但是额外的创建函数不会被缓存;它们将在每次调用时被调用。
这是为了支持构建烘焙查询的特定步骤使查询无法缓存的情况,例如依赖于某些不可缓存值的变体。
参数:
full – 如果为 False,则仅在 spoil 步骤之后添加到此BakedQuery
对象的函数将不被缓存;直到此点为止的BakedQuery
状态将从缓存中提取。如果为 True,则每次都会从头开始构建整个Query
对象,每次调用都会调用所有创建函数。
method to_query(query_or_session)
返回用作子查询的Query
对象。
此方法应在用于生成封闭BakedQuery
步骤的 lambda 可调用内使用。参数通常应为传递给 lambda 的Query
对象:
sub_bq = self.bakery(lambda s: s.query(User.name)) sub_bq += lambda q: q.filter( User.id == Address.user_id).correlate(Address) main_bq = self.bakery(lambda s: s.query(Address)) main_bq += lambda q: q.filter( sub_bq.to_query(q).exists())
在第一个可调用中使用子查询针对Session
的情况下,也接受Session
:
sub_bq = self.bakery(lambda s: s.query(User.name)) sub_bq += lambda q: q.filter( User.id == Address.user_id).correlate(Address) main_bq = self.bakery( lambda s: s.query( Address.id, sub_bq.to_query(q).scalar_subquery()) )
参数:
query_or_session –
一个Query
对象或一个类Session
对象,假定在封闭BakedQuery
可调用的上下文中。
版本 1.3 中新增。
method with_criteria(fn, *args)
向从此克隆的BakedQuery
添加一个条件函数。
这相当于使用+
运算符生成具有修改的新BakedQuery
。
class sqlalchemy.ext.baked.Bakery
返回一个返回BakedQuery
的可调用对象。
此对象由类方法BakedQuery.bakery()
返回。它作为一个对象存在,以便可以轻松检查“缓存”。
版本 1.2 中新增。
class sqlalchemy.ext.baked.Result
针对Session
调用BakedQuery
。
Result
对象是实际创建或从缓存中检索到的Query
对象,针对目标Session
进行调用以获取结果。
method all()
返回所有行。
等同于Query.all()
。
method count()
返回‘count’。
等同于Query.count()
。
请注意,这使用子查询来确保准确计数,而不考虑原始语句的结构。
method first()
返回第一行。
等同于Query.first()
。
method get(ident)
根据标识检索对象。
等同于Query.get()
。
method one()
返回确切的一个结果或引发异常。
等同于Query.one()
。
method one_or_none()
返回一个或零个结果,或者对于多行会引发异常。
等同于Query.one_or_none()
。
method params(*args, **kw)
指定要替换到字符串 SQL 语句中的参数。
method scalar()
返回第一个结果的第一个元素,如果没有行则返回 None。如果返回多行,则引发 MultipleResultsFound 异常。
等同于Query.scalar()
。
method with_post_criteria(fn)
添加一个将在缓存后应用的条件函数。
这添加了一个将在从缓存中检索到的Query
对象上运行的函数。目前仅包括Query.params()
和Query.execution_options()
方法。
警告
Result.with_post_criteria()
函数应用于查询的Query
对象之后查询的 SQL 语句对象已从缓存中检索。只应使用Query.params()
和Query.execution_options()
方法。
新版本 1.2 中新增。