summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2017-04-21 17:40:11 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2017-04-21 18:12:56 -0400
commite53009e25378990ee48d4c0c6a194d2d8d3ed01e (patch)
tree4ebb6b9297a38737c95d6c8f1443fb9eea594457 /lib/sqlalchemy/orm
parentae3ffcf4ea2c131c720a584c29ae66444d929b77 (diff)
downloadsqlalchemy-e53009e25378990ee48d4c0c6a194d2d8d3ed01e.tar.gz
- update relationship loader docs, backport from
1.2 wip Change-Id: I0a3c4a0166f6feed23a021723233d281fad597ec
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py157
1 files changed, 70 insertions, 87 deletions
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index e67159b0d..423d3f558 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -24,57 +24,34 @@ class Load(Generative, MapperOption):
:class:`.Query` in order to affect how various mapped attributes are
loaded.
- .. versionadded:: 0.9.0 The :meth:`.Load` system is a new foundation for
- the existing system of loader options, including options such as
- :func:`.orm.joinedload`, :func:`.orm.defer`, and others. In
- particular, it introduces a new method-chained system that replaces the
- need for dot-separated paths as well as "_all()" options such as
- :func:`.orm.joinedload_all`.
-
- A :class:`.Load` object can be used directly or indirectly. To use one
- directly, instantiate given the parent class. This style of usage is
- useful when dealing with a :class:`.Query` that has multiple entities,
- or when producing a loader option that can be applied generically to
- any style of query::
+ The :class:`.Load` object is in most cases used implicitly behind the
+ scenes when one makes use of a query option like :func:`.joinedload`,
+ :func:`.defer`, or similar. However, the :class:`.Load` object
+ can also be used directly, and in some cases can be useful.
- myopt = Load(MyClass).joinedload("widgets")
-
- The above ``myopt`` can now be used with :meth:`.Query.options`::
+ To use :class:`.Load` directly, instantiate it with the target mapped
+ class as the argument. This style of usage is
+ useful when dealing with a :class:`.Query` that has multiple entities::
- session.query(MyClass).options(myopt)
+ myopt = Load(MyClass).joinedload("widgets")
- The :class:`.Load` construct is invoked indirectly whenever one makes use
- of the various loader options that are present in ``sqlalchemy.orm``,
- including options such as :func:`.orm.joinedload`, :func:`.orm.defer`,
- :func:`.orm.subqueryload`, and all the rest. These constructs produce an
- "anonymous" form of the :class:`.Load` object which tracks attributes and
- options, but is not linked to a parent class until it is associated with a
- parent :class:`.Query`::
+ The above ``myopt`` can now be used with :meth:`.Query.options`, where it
+ will only take effect for the ``MyClass`` entity::
- # produce "unbound" Load object
- myopt = joinedload("widgets")
+ session.query(MyClass, MyOtherClass).options(myopt)
- # when applied using options(), the option is "bound" to the
- # class observed in the given query, e.g. MyClass
- session.query(MyClass).options(myopt)
+ One case where :class:`.Load` is useful as public API is when specifying
+ "wildcard" options that only take effect for a certain class::
- Whether the direct or indirect style is used, the :class:`.Load` object
- returned now represents a specific "path" along the entities of a
- :class:`.Query`. This path can be traversed using a standard
- method-chaining approach. Supposing a class hierarchy such as ``User``,
- ``User.addresses -> Address``, ``User.orders -> Order`` and
- ``Order.items -> Item``, we can specify a variety of loader options along
- each element in the "path"::
+ session.query(Order).options(Load(Order).lazyload('*'))
- session.query(User).options(
- joinedload("addresses"),
- subqueryload("orders").joinedload("items")
- )
+ Above, all relationships on ``Order`` will be lazy-loaded, but other
+ attributes on those descendant objects will load using their normal
+ loader strategy.
- Where above, the ``addresses`` collection will be joined-loaded, the
- ``orders`` collection will be subquery-loaded, and within that subquery
- load the ``items`` collection will be joined-loaded.
+ .. seealso::
+ :ref:`loading_toplevel`
"""
@@ -731,6 +708,8 @@ def contains_eager(loadopt, attr, alias=None):
.. seealso::
+ :ref:`loading_toplevel`
+
:ref:`contains_eager`
"""
@@ -817,11 +796,13 @@ def joinedload(loadopt, attr, innerjoin=None):
query(User).options(joinedload(User.orders))
# joined-load Order.items and then Item.keywords
- query(Order).options(joinedload(Order.items).joinedload(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))
+ query(Order).options(
+ lazyload(Order.items).joinedload(Item.keywords))
:param innerjoin: if ``True``, indicates that the joined eager load should
use an inner join instead of the default of left outer join::
@@ -838,22 +819,22 @@ def joinedload(loadopt, attr, innerjoin=None):
The above query, linking A.bs via "outer" join and B.cs via "inner" join
would render the joins as "a LEFT OUTER JOIN (b JOIN c)". When using
- SQLite, this form of JOIN is translated to use full subqueries as this
- syntax is otherwise not directly supported.
+ older versions of SQLite (< 3.7.16), this form of JOIN is translated to
+ use full subqueries as this syntax is otherwise not directly supported.
The ``innerjoin`` flag can also be stated with the term ``"unnested"``.
- This will prevent joins from being right-nested, and will instead
- link an "innerjoin" eagerload to an "outerjoin" eagerload by bypassing
- the "inner" join. Using this form as follows::
+ This indicates that an INNER JOIN should be used, *unless* the join
+ is linked to a LEFT OUTER JOIN to the left, in which case it
+ will render as LEFT OUTER JOIN. For example, supposing ``A.bs``
+ is an outerjoin::
query(A).options(
- joinedload(A.bs, innerjoin=False).
+ joinedload(A.bs).
joinedload(B.cs, innerjoin="unnested")
)
- Joins will be rendered as "a LEFT OUTER JOIN b LEFT OUTER JOIN c", so that
- all of "a" is matched rather than being incorrectly limited by a "b" that
- does not contain a "c".
+ The above join will render as "a LEFT OUTER JOIN b LEFT OUTER JOIN c",
+ rather than as "a LEFT OUTER JOIN (b JOIN c)".
.. note:: The "unnested" flag does **not** affect the JOIN rendered
from a many-to-many association table, e.g. a table configured
@@ -861,9 +842,6 @@ def joinedload(loadopt, attr, innerjoin=None):
correctness of results, these joins are always INNER and are
therefore right-nested if linked to an OUTER join.
- .. versionadded:: 0.9.4 Added support for "nesting" of eager "inner"
- joins. See :ref:`feature_2976`.
-
.. versionchanged:: 1.0.0 ``innerjoin=True`` now implies
``innerjoin="nested"``, whereas in 0.9 it implied
``innerjoin="unnested"``. In order to achieve the pre-1.0 "unnested"
@@ -875,7 +853,8 @@ def joinedload(loadopt, attr, innerjoin=None):
The joins produced by :func:`.orm.joinedload` are **anonymously
aliased**. The criteria by which the join proceeds cannot be
modified, nor can the :class:`.Query` refer to these joins in any way,
- including ordering.
+ including ordering. See :ref:`zen_of_eager_loading` for further
+ detail.
To produce a specific SQL JOIN which is explicitly available, use
:meth:`.Query.join`. To combine explicit JOINs with eager loading
@@ -886,16 +865,7 @@ def joinedload(loadopt, attr, innerjoin=None):
:ref:`loading_toplevel`
- :ref:`contains_eager`
-
- :func:`.orm.subqueryload`
-
- :func:`.orm.lazyload`
-
- :paramref:`.relationship.lazy`
-
- :paramref:`.relationship.innerjoin` - :func:`.relationship`-level
- version of the :paramref:`.joinedload.innerjoin` option.
+ :ref:`joined_eager_loading`
"""
loader = loadopt.set_relationship_strategy(attr, {"lazy": "joined"})
@@ -941,11 +911,7 @@ def subqueryload(loadopt, attr):
:ref:`loading_toplevel`
- :func:`.orm.joinedload`
-
- :func:`.orm.lazyload`
-
- :paramref:`.relationship.lazy`
+ :ref:`subquery_eager_loading`
"""
return loadopt.set_relationship_strategy(attr, {"lazy": "subquery"})
@@ -971,7 +937,9 @@ def lazyload(loadopt, attr):
.. seealso::
- :paramref:`.relationship.lazy`
+ :ref:`loading_toplevel`
+
+ :ref:`lazy_loading`
"""
return loadopt.set_relationship_strategy(attr, {"lazy": "select"})
@@ -999,12 +967,6 @@ def immediateload(loadopt, attr):
:ref:`loading_toplevel`
- :func:`.orm.joinedload`
-
- :func:`.orm.lazyload`
-
- :paramref:`.relationship.lazy`
-
"""
loader = loadopt.set_relationship_strategy(attr, {"lazy": "immediate"})
return loader
@@ -1026,6 +988,10 @@ def noload(loadopt, attr):
:func:`.orm.noload` applies to :func:`.relationship` attributes; for
column-based attributes, see :func:`.orm.defer`.
+ .. seealso::
+
+ :ref:`loading_toplevel`
+
"""
return loadopt.set_relationship_strategy(attr, {"lazy": "noload"})
@@ -1060,6 +1026,12 @@ def raiseload(loadopt, attr, sql_only=False):
.. versionadded:: 1.1
+ .. seealso::
+
+ :ref:`loading_toplevel`
+
+ :ref:`prevent_lazy_with_raiseload`
+
"""
return loadopt.set_relationship_strategy(
@@ -1075,19 +1047,30 @@ def raiseload(*keys, **kw):
def defaultload(loadopt, attr):
"""Indicate an attribute should load using its default loader style.
- This method is used to link to other loader options, such as
- to set the :func:`.orm.defer` option on a class that is linked to
- a relationship of the parent class being loaded, :func:`.orm.defaultload`
- can be used to navigate this path without changing the loading style
- of the relationship::
+ This method is used to link to other loader options further into
+ a chain of attributes without altering the loader style of the links
+ along the chain. For example, to set joined eager loading for an
+ element of an element::
- session.query(MyClass).options(defaultload("someattr").defer("some_column"))
+ session.query(MyClass).options(
+ defaultload(MyClass.someattribute).
+ joinedload(MyOtherClass.someotherattribute)
+ )
+
+ :func:`.defaultload` is also useful for setting column-level options
+ on a related class, namely that of :func:`.defer` and :func:`.undefer`::
+
+ session.query(MyClass).options(
+ defaultload(MyClass.someattribute).
+ defer("some_column").
+ undefer("some_other_column")
+ )
.. seealso::
- :func:`.orm.defer`
+ :ref:`relationship_loader_options`
- :func:`.orm.undefer`
+ :ref:`deferred_loading_w_multiple`
"""
return loadopt.set_relationship_strategy(