版本:1.1.0b2 |发布日期:2016年7月1日

SQLAlchemy 1.1文档

关系加载技术

SQLAlchemy的很大一部分是对查询中相关对象加载的方式提供了广泛的控制。此行为可以在映射器构造时使用relationship()函数的lazy参数进行配置,也可以使用Query目的。

使用Loader策略:Lazy Loading,Eager Loading

默认情况下,所有的对象间关系都是延迟加载relationship()关联的标量或集合属性包含一个触发器,该属性首次被访问时触发。除了一种情况外,这个触发器在访问点发出一个SQL调用来加载相关的对象或对象:

sql>>> jack.addresses
[<Address(u'jack@google.com')>, <Address(u'j25@yahoo.com')>]

在没有发出SQL的情况下,对于一个简单的多对一关系,当相关对象可以通过主键唯一标识并且该对象已经存在于当前Session中时。

“加载属性访问”的默认行为称为“延迟”或“选择”加载 - 名称“select”,因为通常在首次访问属性时发出“SELECT”语句。

Object Relational Tutorial中,我们引入了Eager Loading的概念。我们使用optionQuery对象结合,以表明在单个SQL查询中应该与父对象同时加载关系。这个被称为joinedload()的选项将JOIN(缺省为LEFT OUTER连接)连接到语句,并从与父类相同的结果集中填充标量/集合:

sql>>> jack = session.query(User).\
... options(joinedload('addresses')).\
... filter_by(name='jack').all() #doctest: +NORMALIZE_WHITESPACE

除了“加入急切加载”之外,还有第二种急切加载选项,称为“子查询急切加载”。这种热切的加载为所请求的每个集合都发出额外的SQL语句,并聚合到所有父对象中:

sql>>> jack = session.query(User).\
... options(subqueryload('addresses')).\
... filter_by(name='jack').all()

任何relationship()的默认加载器策略lazy关键字参数配置,默认为select这表示一个“选择”语句。下面我们将它设置为joined,以便使用JOIN加载children关系:

# load the 'children' collection using LEFT OUTER JOIN
class Parent(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)
    children = relationship("Child", lazy='joined')

我们还可以使用subquery将其设置为对所有集合使用第二个查询进行热切加载:

# load the 'children' collection using a second query which
# JOINS to a subquery of the original
class Parent(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)
    children = relationship("Child", lazy='subquery')

在查询时,使用joinedload()subqueryload()lazyload()

# set children to load lazily
session.query(Parent).options(lazyload('children')).all()

# set children to load eagerly with a join
session.query(Parent).options(joinedload('children')).all()

# set children to load eagerly with a second statement
session.query(Parent).options(subqueryload('children')).all()

订购的重要性

A query which makes use of subqueryload() in conjunction with a limiting modifier such as Query.first(), Query.limit(), or Query.offset() should always include Query.order_by() against unique column(s) such as the primary key, so that the additional queries emitted by subqueryload() include the same ordering as used by the parent query. 没有它,内部查询有可能返回错误的行:

# incorrect, no ORDER BY
session.query(User).options(subqueryload(User.addresses)).first()

# incorrect if User.name is not unique
session.query(User).options(subqueryload(User.addresses)).order_by(User.name).first()

# correct
session.query(User).options(subqueryload(User.addresses)).order_by(User.name, User.id).first()

沿路径加载

为了引用比一个层次更深的关系,可以使用方法链接。所有加载器选项返回的对象是Load类的一个实例,它提供了一个所谓的“生成”接口:

session.query(Parent).options(
                            joinedload('foo').
                                joinedload('bar').
                                joinedload('bat')
                            ).all()

使用方法链,路径中每个链接的加载器样式都被明确地声明。为了在不改变特定属性的现有装载器风格的情况下沿着路径导航,可以使用defaultload()方法/函数:

session.query(A).options(
                    defaultload("atob").joinedload("btoc")
                ).all()

在0.9.0版本中改变:以前在加载器选项中指定点分隔路径的方法已被Load对象和相关方法的模糊方法所取代。使用这个系统,用户明确指定链中每个链接的加载样式,而不是在诸如joinedload()joinedload_all()之类的选项之间进行猜测。提供orm.defaultload()以允许在不修改现有的加载器选项的情况下进行路径导航。点分隔的路径系统以及_all()函数将无限期地保持向后兼容。

默认加载策略

New in version 0.7.5: Default loader strategies as a new feature.

Each of joinedload(), subqueryload(), lazyload(), noload(), and raiseload() can be used to set the default style of relationship() loading for a particular query, affecting all relationship() -mapped attributes not otherwise specified in the Query. 通过将字符串'*'作为参数传递给以下任何选项,可以使用此功能:

session.query(MyClass).options(lazyload('*'))

在上面,lazyload('*')选项将取代用于该查询的所有relationship()结构的lazy设置,那些使用'dynamic'风格的加载。例如,如果某些关系指定了lazy='joined'lazy='subquery',则单方面导致使用lazyload('*')所有这些关系使用'select'加载,例如当每个属性被访问时发出一个SELECT语句。

该选项不会取代查询中指定的加载器选项,如eagerload()subqueryload()等。下面的查询仍将使用widget关系的连接加载:

session.query(MyClass).options(
                            lazyload('*'),
                            joinedload(MyClass.widget)
                        )

如果传递多个'*'选项,则最后一个覆盖先前传递的选项。

每个实体的默认加载策略

版本0.9.0中的新功能:每个实体的默认加载器策略。

默认加载器策略的一个变体是能够以每个实体为基础设置策略。例如,如果查询UserAddress,我们可以指示Address上的所有关系仅使用延迟加载,方法是首先应用Load对象,然后指定*作为链接选项:

session.query(User, Address).options(Load(Address).lazyload('*'))

以上,Address上的所有关系都将被设置为延迟加载。

渴望的载入载入

The philosophy behind loader strategies is that any set of loading schemes can be applied to a particular query, and the results don’t change - only the number of SQL statements required to fully load related objects and collections changes. 一个特定的查询可能会开始使用所有的延迟加载。在上下文中使用它之后,可能会发现总是访问特定的属性或集合,并且更改这些策略的加载策略会更有效率。该策略可以在没有其他修改的情况下进行更改,结果将保持一致,但是会发出更少的SQL语句。在理论上(而且在实践中),对于Query可以做的任何事情都不会根据加载器策略的变化加载一组不同的主或相关对象。

特别是joinedload()如何实现不影响以任何方式返回的实体行的结果是它创建了它添加到查询的连接的匿名别名,以便它们不能被引用查询的其他部分。For example, the query below uses joinedload() to create a LEFT OUTER JOIN from users to addresses, however the ORDER BY added against Address.email_address is not valid - the Address entity is not named in the query:

>>> jack = session.query(User).\
... options(joinedload(User.addresses)).\
... filter(User.name=='jack').\
... order_by(Address.email_address).all()
SELECT addresses_1.id AS addresses_1_id, addresses_1.email_address AS addresses_1_email_address, addresses_1.user_id AS addresses_1_user_id, users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id WHERE users.name = ? ORDER BY addresses.email_address <-- this part is wrong ! ['jack']

Above, ORDER BY addresses.email_address is not valid since addresses is not in the FROM list. 加载User通过电子邮件地址记录和订购的正确方法是使用Query.join()

>>> jack = session.query(User).\
... join(User.addresses).\
... filter(User.name=='jack').\
... order_by(Address.email_address).all()
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users JOIN addresses ON users.id = addresses.user_id WHERE users.name = ? ORDER BY addresses.email_address ['jack']

上面的语句当然与前面的语句不同,因为addresses中的列根本不包含在结果中。我们可以加入joinedload(),以便有两个连接 - 一个是我们要订购的,另一个是匿名使用来加载User.addresses

>>> jack = session.query(User).\
... join(User.addresses).\
... options(joinedload(User.addresses)).\
... filter(User.name=='jack').\
... order_by(Address.email_address).all()
SELECT addresses_1.id AS addresses_1_id, addresses_1.email_address AS addresses_1_email_address, addresses_1.user_id AS addresses_1_user_id, users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users JOIN addresses ON users.id = addresses.user_id LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id WHERE users.name = ? ORDER BY addresses.email_address ['jack']

What we see above is that our usage of Query.join() is to supply JOIN clauses we’d like to use in subsequent query criterion, whereas our usage of joinedload() only concerns itself with the loading of the User.addresses collection, for each User in the result. 在这种情况下,这两个连接最有可能看起来是多余的 - 它们是什么。If we wanted to use just one JOIN for collection loading as well as ordering, we use the contains_eager() option, described in Routing Explicit Joins/Statements into Eagerly Loaded Collections below. But to see why joinedload() does what it does, consider if we were filtering on a particular Address:

>>> jack = session.query(User).\
... join(User.addresses).\
... options(joinedload(User.addresses)).\
... filter(User.name=='jack').\
... filter(Address.email_address=='someaddress@foo.com').\
... all()
SELECT addresses_1.id AS addresses_1_id, addresses_1.email_address AS addresses_1_email_address, addresses_1.user_id AS addresses_1_user_id, users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users JOIN addresses ON users.id = addresses.user_id LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id WHERE users.name = ? AND addresses.email_address = ? ['jack', 'someaddress@foo.com']

上面,我们可以看到两个JOIN角色非常不同。一个将匹配UserAddress的其中一个行,即Address.email_address=='someaddress@foo.com'的连接。The other LEFT OUTER JOIN will match all Address rows related to User, and is only used to populate the User.addresses collection, for those User objects that are returned.

通过将joinedload()的使用更改为另一种加载类型,我们可以更改集合的加载方式,完全独立于用于检索我们想要的实际User行的SQL。下面我们把joinedload()改成subqueryload()

>>> jack = session.query(User).\
... join(User.addresses).\
... options(subqueryload(User.addresses)).\
... filter(User.name=='jack').\
... filter(Address.email_address=='someaddress@foo.com').\
... all()
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users JOIN addresses ON users.id = addresses.user_id WHERE users.name = ? AND addresses.email_address = ? ['jack', 'someaddress@foo.com'] # ... subqueryload() emits a SELECT in order # to load all address records ...

当使用连接的预先加载时,如果查询包含一个影响从外部返回到连接的行的修饰符,例如当使用DISTINCT,LIMIT,OFFSET或等价物时,完成的语句首先包装在子查询中,加入的急切加载应用于子查询。SQLAlchemy的加入的加载会花费更多的时间,然后进一步增加10英里,以确保它不会影响查询的最终结果,而不管查询的格式是什么,只加载集合和相关对象的方式。

使用什么样的加载?

使用哪种类型的加载通常归结为优化SQL执行次数,所发出的SQL的复杂性以及获取的数据量之间的折衷。让我们举两个例子:引用集合的relationship()和引用标量多对一引用的relationship()

  • 一对多收藏
  • 当使用默认的延迟加载时,如果加载100个对象,然后访问每个对象的集合,则会发出总共101个SQL语句,尽管每个语句通常都是一个简单的SELECT,没有任何联接。
  • 当使用连接的加载时,100个对象及其集合的加载只会发出一条SQL语句。但是,获取的总行数将等于所有集合大小的总和,对于每个拥有一个空集合的父对象,再加上一行。每行还将包含由父节点表示的全部列,对每个集合项重复 - SQLAlchemy不会重新获取主键以外的这些列,但大多数DBAPI(有一些例外)将传输完整数据在任何情况下,每个父母通过电线连接到客户端连接。因此,只有当收集的大小相对较小时,加入的急切加载才有意义。与INNER加入相比,LEFT OUTER JOIN也可以是性能密集型的。
  • 使用子查询加载时,100个对象的加载将发出两个SQL语句。第二条语句将获取等于所有集合大小总和的行数。使用INNER JOIN,并请求最少的父列,只有主键。因此,当集合较大时,子查询负载是有意义的。
  • 当在连接或子查询加载中使用多级深度时,加载集合中的集合将乘以以笛卡尔方式获取的行的总数。这两种形式的热切加载总是从原始父类加入。
  • 多对一的参考
  • 当使用默认的延迟加载时,在收集的情况下,100个对象的加载会发出多达101个SQL语句。然而 - 有一个显著的例外,因为如果多到一个参考是一个简单的外键参照目标的主键,每个参考将首先使用检查当前的身份映射Query.get()因此,在这里,如果对象集合引用相对较小的目标对象集合,或者完整的可能目标对象集合已经被加载到会话中并被强引用,则使用默认的lazy ='select'是迄今为止最有效的方法。
  • 使用连接加载时,100个对象的加载只会发出一条SQL语句。连接将是一个LEFT OUTER JOIN,在所有情况下总的行数将等于100。如果你知道每个父对象都有一个子对象(即外键引用不是NULL),那么可以将innerjoin设置为Truerelationship()中指定。对于有很多可能的目标引用可能尚未加载的对象的加载,使用INNER JOIN加载加载非常有效。
  • 子查询加载将为所有子对象发出第二个加载,因此对于100个对象的加载,将会有两个SQL语句发出。然而,除了可能在子查询加载可以在所有情况下都使用INNER JOIN,而加入的加载要求外键不是NULL,在这里可能没有太多的优势。

将显式联接/语句路由到预先加载的集合

joinedload()的行为是这样的,连接是自动创建的,使用匿名别名作为目标,其结果被路由到加载对象的集合和标量引用。通常情况下,一个查询已经包含了代表特定集合或标量引用的必要连接,并且由连接的加载特性添加的连接是多余的 - 但是您仍然希望集合/引用被填充。

为此SQLAlchemy提供contains_eager()选项。除了假设Query将显式指定适当的连接外,该选项的使用方式与joinedload()选项相同。下面我们指定UserAddress之间的连接,并将其作为加载User.addresses的基础:

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    addresses = relationship("Address")

class Address(Base):
    __tablename__ = 'address'

    # ...

q = session.query(User).join(User.addresses).\
            options(contains_eager(User.addresses))

如果语句的“热切”部分是“别名”,则可以使用contains_eager()alias关键字参数来指示它。这是作为对aliased()Alias结构的引用发送的:

# use an alias of the Address entity
adalias = aliased(Address)

# construct a Query object which expects the "addresses" results
query = session.query(User).\
    outerjoin(adalias, User.addresses).\
    options(contains_eager(User.addresses, alias=adalias))

# get results normally
sqlr = query.all()

The path given as the argument to contains_eager() needs to be a full path from the starting entity. 例如,如果我们加载了Users->orders->Order->items->Item,字符串版本将如下所示:

query(User).options(contains_eager('orders').contains_eager('items'))

或者使用类绑定描述符:

query(User).options(contains_eager(User.orders).contains_eager(Order.items))

使用contains_eager()来加载一个自定义过滤的集合结果

When we use contains_eager(), we are constructing ourselves the SQL that will be used to populate collections. 由此可见,我们可以通过编写SQL来为集合或标量属性加载元素的子集来选择修改集合要存储的值。

作为一个例子,我们可以加载一个User对象,并且仅仅通过过滤来只加载特定的地址到.addresses

q = session.query(User).join(User.addresses).\
            filter(Address.email.like('%ed%')).\
            options(contains_eager(User.addresses))

The above query will load only User objects which contain at least Address object that contains the substring 'ed' in its email field; the User.addresses collection will contain only these Address entries, and not any other Address entries that are in fact associated with the collection.

警告

请记住,当我们只将对象的子集加载到集合中时,该集合不再代表数据库中的实际内容。如果我们尝试向这个集合中添加条目,我们可能会发现自己与已经在数据库中但未本地加载的条目冲突。

另外,一旦对象或属性过期,集合将完全正常地重新加载This expiration occurs whenever the Session.commit(), Session.rollback() methods are used assuming default session settings, or the Session.expire_all() or Session.expire() methods are used.

由于这些原因,当需要一个对象加上一组自定义的相关对象时,宁愿返回一个元组中的单独的字段而不是人为地改变一个集合:

q = session.query(User, Address).join(User.addresses).\
            filter(Address.email.like('%ed%'))

任意语句的高级用法

可以更加创造性地使用alias参数,因为它可以表示任何一组任意名称以匹配到一个语句中。在它下面链接到一个将一组列对象链接到一个字符串SQL语句的select()

# label the columns of the addresses table
eager_columns = select([
                    addresses.c.address_id.label('a1'),
                    addresses.c.email_address.label('a2'),
                    addresses.c.user_id.label('a3')])

# select from a raw SQL statement which uses those label names for the
# addresses table.  contains_eager() matches them up.
query = session.query(User).\
    from_statement("select users.*, addresses.address_id as a1, "
            "addresses.email_address as a2, addresses.user_id as a3 "
            "from users left outer join addresses on users.user_id=addresses.user_id").\
    options(contains_eager(User.addresses, alias=eager_columns))

创建自定义加载规则

警告

这是一种先进的技术!应该非常小心和测试。

ORM具有各种边缘情况,其中属性的值是本地可用的,但是ORM本身并不知晓这一点。还有一些情况是用户定义的加载属性系统是可取的。为了支持用户定义的加载系统的用例,提供了一个关键函数attributes.set_committed_value()这个函数基本上等同于Python本身的setattr()函数,只是当应用于目标对象时,用于确定刷新时间变化的SQLAlchemy的“属性历史记录”系统被绕过;该属性的分配方式与ORM从数据库中加载该属性的方式相同。

当一个对象被加载时,attributes.set_committed_value()的使用可以与另一个被称为InstanceEvents.load()的关键事件结合起来以产生属性填充行为。一个这样的例子是双向的“一对一”情况,其中加载一对一的“多对一”方面也应该暗示“一对多”方的价值。SQLAlchemy ORM在加载相关对象时不会考虑backrefs,它将“one-to-one”视为另一个“一对多”,恰好是一行。

鉴于以下映射:

from sqlalchemy import Integer, ForeignKey, Column
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)
    b_id = Column(ForeignKey('b.id'))
    b = relationship("B", backref=backref("a", uselist=False), lazy='joined')


class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)

如果我们查询一个A行,然后询问a.b.a,我们将得到一个额外的SELECT:

>>> a1.b.a
SELECT a.id AS a_id, a.b_id AS a_b_id
FROM a
WHERE ? = a.b_id

This SELECT is redundant becasue b.a is the same value as a1. 我们可以创建一个有效的规则来为我们填充这个:

from sqlalchemy import event
from sqlalchemy.orm import attributes

@event.listens_for(A, "load")
def load_b(target, context):
    if 'b' in target.__dict__:
        attributes.set_committed_value(target.b, 'a', target)

现在当我们查询A时,我们将从我们的事件中获得A.b从加入的负载和A.b.a

sqla1 = s.query(A).first()
assert a1.b.a is a1

Relationship Loader API

sqlalchemy.orm。 T0> contains_alias T1> ( T2> 别名 T3> ) T4> ¶ T5 >

返回将向Query指出主表已被别名的MapperOption

这是一个很少用的选项,以适应contains_eager()结合使用用户定义的SELECT语句来替代父表的罕见情况。例如。:

# define an aliased UNION called 'ulist'
ulist = users.select(users.c.user_id==7).\
                union(users.select(users.c.user_id>7)).\
                alias('ulist')

# add on an eager load of "addresses"
statement = ulist.outerjoin(addresses).\
                select().apply_labels()

# create query, indicating "ulist" will be an
# alias for the main table, "addresses"
# property should be eager loaded
query = session.query(User).options(
                        contains_alias(ulist),
                        contains_eager(User.addresses))

# then get results via the statement
results = query.from_statement(statement).all()
参数:alias – is the string name of an alias, or a Alias object representing the alias.
sqlalchemy.orm.contains_eager(*keys, **kw)

指出应该从查询中手动指定的列中急切加载给定的属性。

这个函数是Load接口的一部分,支持方法链接和独立操作。

该选项与加载所需行的显式连接一起使用,即:

sess.query(Order).\
        join(Order.user).\
        options(contains_eager(Order.user))

上面的查询将从Order实体连接到其相关的User实体,并且返回的Order对象将具有Order.user属性预先填充。

contains_eager() also accepts an alias argument, which is the string name of an alias, an alias() construct, or an aliased() construct. 当急切加载的行来自一个别名表时使用这个:

user_alias = aliased(User)
sess.query(Order).\
        join((user_alias, Order.user)).\
        options(contains_eager(Order.user, alias=user_alias))
sqlalchemy.orm。 T0> defaultload T1> ( T2> *键 T3> ) T4> ¶ T5>

指示应使用其默认加载程序样式加载的属性。

This method is used to link to other loader options, such as to set the orm.defer() option on a class that is linked to a relationship of the parent class being loaded, orm.defaultload() can be used to navigate this path without changing the loading style of the relationship:

session.query(MyClass).options(defaultload("someattr").defer("some_column"))
sqlalchemy.orm eagerload * args** kwargs ) T5> ¶ T6>

joinedload()的同义词。

sqlalchemy.orm.eagerload_all(*args, **kwargs)

joinedload_all()的同义词

sqlalchemy.orm。 T0> immediateload T1> ( T2> *键 T3> ) T4> ¶ T5>

表明给定的属性应该使用立即加载和每个属性的SELECT语句加载。

这个函数是Load接口的一部分,支持方法链接和独立操作。

sqlalchemy.orm.joinedload(*keys, **kw)

表明给定的属性应该使用加入的加载加载。

这个函数是Load接口的一部分,支持方法链接和独立操作。

例子:

# joined-load the "orders" collection on "User"
query(User).options(joinedload(User.orders))

# joined-load Order.items and then Item.keywords
query(Order).options(joinedload(Order.items).joinedload(Item.keywords))

# lazily load Order.items, but when Items are loaded,
# joined-load the keywords collection
query(Order).options(lazyload(Order.items).joinedload(Item.keywords))
参数: innerjoin -

如果True,则表示加入的预载加载应该使用内连接而不是左外连接的默认加载:

query(Order).options(joinedload(Order.user, innerjoin=True))

为了将多个渴望的连接链接在一起,其中一些可能是OUTER和其他INNER,右嵌套连接被用来链接它们:

query(A).options(
    joinedload(A.bs, innerjoin=False).
        joinedload(B.cs, innerjoin=True)
)

上面的查询,通过“外部”连接链接A.bs和通过“内部”连接链接B.cs会将连接呈现为“左侧外部连接(b JOIN c)”。当使用SQLite时,JOIN的这种形式被转换为使用完整的子查询,否则不直接支持这种语法。

也可以用"unnested"来表示innerjoin标志。这将防止连接被嵌套,并且将通过绕过“内部”连接而将“内连接”预紧装置连接到“外连接”预紧装置。使用这个表格如下:

query(A).options(
    joinedload(A.bs, innerjoin=False).
        joinedload(B.cs, innerjoin="unnested")
)

连接将被渲染为“左外连接b左外连接c”,以便所有的“a”匹配而不是被不包含“c”的“b”不正确地限制。

注意

The “unnested” flag does not affect the JOIN rendered from a many-to-many association table, e.g. a table configured as relationship.secondary, to the target table; for correctness of results, these joins are always INNER and are therefore right-nested if linked to an OUTER join.

New in version 0.9.4: Added support for “nesting” of eager “inner” joins. 请参阅Right-nested inner joins available in joined eager loads

版本1.0.0改变: innerjoin=True现在意味着innerjoin="nested",而在0.9中暗示innerjoin="unnested"为了实现1.0之前的“unnested”内部联接行为,请使用值innerjoin="unnested"请参见Right inner join nesting now the default for joinedload with innerjoin=True的joinedload的缺省值。

注意

orm.joinedload()生成的连接是匿名别名连接进行的标准无法修改,Query也不能以任何方式引用这些连接,包括排序。

要产生明确可用的特定SQL JOIN,请使用Query.join()要将显式JOIN与急切的集合加载结合起来,请使用orm.contains_eager();请参见Routing Explicit Joins/Statements into Eagerly Loaded Collections

sqlalchemy.orm.joinedload_all(*keys, **kw)

orm.joinedload()生成一个独立的“全部”选项。

从版本0.9.0开始弃用:“_all()”样式被方法链接取代,例如:

session.query(MyClass).options(
    joinedload("someattribute").joinedload("anotherattribute")
)
sqlalchemy.orm。 T0> lazyload T1> ( T2> *键 T3> ) T4> ¶ T5>

表明给定的属性应该使用“懒”加载加载。

这个函数是Load接口的一部分,支持方法链接和独立操作。

也可以看看

relationship.lazy

sqlalchemy.orm。 T0> 空载 T1> ( T2> *键 T3> ) T4> ¶ T5>

表明给定的关系属性应保持卸载。

这个函数是Load接口的一部分,支持方法链接和独立操作。

orm.noload() applies to relationship() attributes; for column-based attributes, see orm.defer().

sqlalchemy.orm。 T0> raiseload T1> ( T2> *键 T3> ) T4> ¶ T5>

表明给定的关系属性应该禁止延迟加载。

使用orm.raiseload()配置的关系属性将在访问时引发InvalidRequestError这是有用的典型方式是当应用程序试图确保在特定上下文中访问的所有关系属性已经通过预先加载被加载时。而不必通过SQL日志读取,以确保没有发生延迟加载,这种策略将导致他们立即提高。

这个函数是Load接口的一部分,支持方法链接和独立操作。

orm.raiseload() applies to relationship() attributes only.

版本1.1中的新功能

sqlalchemy.orm。 T0> subqueryload T1> ( T2> *键 T3> ) T4> ¶ T5>

指出应该使用子查询加载加载给定的属性。

这个函数是Load接口的一部分,支持方法链接和独立操作。

例子:

# subquery-load the "orders" collection on "User"
query(User).options(subqueryload(User.orders))

# subquery-load Order.items and then Item.keywords
query(Order).options(subqueryload(Order.items).subqueryload(Item.keywords))

# lazily load Order.items, but when Items are loaded,
# subquery-load the keywords collection
query(Order).options(lazyload(Order.items).subqueryload(Item.keywords))
sqlalchemy.orm。 T0> subqueryload_all T1> ( T2> *键 T3> ) T4> ¶ T5>

orm.subqueryload()生成一个独立的“全部”选项。

从版本0.9.0开始弃用:“_all()”样式被方法链接取代,例如:

session.query(MyClass).options(
    subqueryload("someattribute").subqueryload("anotherattribute")
)