summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/relationships.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/relationships.py')
-rw-r--r--lib/sqlalchemy/orm/relationships.py522
1 files changed, 282 insertions, 240 deletions
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index 90e3085a0..c2debda03 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -25,7 +25,8 @@ from ..sql.util import (
_deep_deannotate, selectables_overlap
)
from ..sql import operators, expression, visitors
-from .interfaces import MANYTOMANY, MANYTOONE, ONETOMANY, StrategizedProperty, PropComparator
+from .interfaces import (MANYTOMANY, MANYTOONE, ONETOMANY,
+ StrategizedProperty, PropComparator)
from ..inspection import inspect
from . import mapper as mapperlib
import collections
@@ -116,8 +117,9 @@ class RelationshipProperty(StrategizedProperty):
info=None):
"""Provide a relationship between two mapped classes.
- This corresponds to a parent-child or associative table relationship. The
- constructed class is an instance of :class:`.RelationshipProperty`.
+ This corresponds to a parent-child or associative table relationship.
+ The constructed class is an instance of
+ :class:`.RelationshipProperty`.
A typical :func:`.relationship`, used in a classical mapping::
@@ -128,10 +130,11 @@ class RelationshipProperty(StrategizedProperty):
Some arguments accepted by :func:`.relationship` optionally accept a
callable function, which when called produces the desired value.
The callable is invoked by the parent :class:`.Mapper` at "mapper
- initialization" time, which happens only when mappers are first used, and
- is assumed to be after all mappings have been constructed. This can be
- used to resolve order-of-declaration and other dependency issues, such as
- if ``Child`` is declared below ``Parent`` in the same file::
+ initialization" time, which happens only when mappers are first used,
+ and is assumed to be after all mappings have been constructed. This
+ can be used to resolve order-of-declaration and other dependency
+ issues, such as if ``Child`` is declared below ``Parent`` in the same
+ file::
mapper(Parent, properties={
"children":relationship(lambda: Child,
@@ -139,12 +142,12 @@ class RelationshipProperty(StrategizedProperty):
})
When using the :ref:`declarative_toplevel` extension, the Declarative
- initializer allows string arguments to be passed to :func:`.relationship`.
- These string arguments are converted into callables that evaluate
- the string as Python code, using the Declarative
- class-registry as a namespace. This allows the lookup of related
- classes to be automatic via their string name, and removes the need to
- import related classes at all into the local module space::
+ initializer allows string arguments to be passed to
+ :func:`.relationship`. These string arguments are converted into
+ callables that evaluate the string as Python code, using the
+ Declarative class-registry as a namespace. This allows the lookup of
+ related classes to be automatic via their string name, and removes the
+ need to import related classes at all into the local module space::
from sqlalchemy.ext.declarative import declarative_base
@@ -157,18 +160,18 @@ class RelationshipProperty(StrategizedProperty):
.. seealso::
- :ref:`relationship_config_toplevel` - Full introductory and reference
- documentation for :func:`.relationship`.
+ :ref:`relationship_config_toplevel` - Full introductory and
+ reference documentation for :func:`.relationship`.
:ref:`orm_tutorial_relationship` - ORM tutorial introduction.
:param argument:
- a mapped class, or actual :class:`.Mapper` instance, representing the
- target of the relationship.
+ a mapped class, or actual :class:`.Mapper` instance, representing
+ the target of the relationship.
- :paramref:`~.relationship.argument` may also be passed as a callable function
- which is evaluated at mapper initialization time, and may be passed as a
- Python-evaluable string when using Declarative.
+ :paramref:`~.relationship.argument` may also be passed as a callable
+ function which is evaluated at mapper initialization time, and may
+ be passed as a Python-evaluable string when using Declarative.
.. seealso::
@@ -188,35 +191,37 @@ class RelationshipProperty(StrategizedProperty):
present in the :class:`.MetaData` collection associated with the
parent-mapped :class:`.Table`.
- The :paramref:`~.relationship.secondary` keyword argument is typically
- applied in the case where the intermediary :class:`.Table` is not
- otherwise exprssed in any direct class mapping. If the "secondary" table
- is also explicitly mapped elsewhere
- (e.g. as in :ref:`association_pattern`), one should consider applying
- the :paramref:`~.relationship.viewonly` flag so that this :func:`.relationship`
- is not used for persistence operations which may conflict with those
- of the association object pattern.
+ The :paramref:`~.relationship.secondary` keyword argument is
+ typically applied in the case where the intermediary :class:`.Table`
+ is not otherwise exprssed in any direct class mapping. If the
+ "secondary" table is also explicitly mapped elsewhere (e.g. as in
+ :ref:`association_pattern`), one should consider applying the
+ :paramref:`~.relationship.viewonly` flag so that this
+ :func:`.relationship` is not used for persistence operations which
+ may conflict with those of the association object pattern.
.. seealso::
- :ref:`relationships_many_to_many` - Reference example of "many to many".
+ :ref:`relationships_many_to_many` - Reference example of "many
+ to many".
:ref:`orm_tutorial_many_to_many` - ORM tutorial introduction to
many-to-many relationships.
- :ref:`self_referential_many_to_many` - Specifics on using many-to-many
- in a self-referential case.
+ :ref:`self_referential_many_to_many` - Specifics on using
+ many-to-many in a self-referential case.
:ref:`declarative_many_to_many` - Additional options when using
Declarative.
- :ref:`association_pattern` - an alternative to :paramref:`~.relationship.secondary`
- when composing association table relationships, allowing additional
- attributes to be specified on the association table.
+ :ref:`association_pattern` - an alternative to
+ :paramref:`~.relationship.secondary` when composing association
+ table relationships, allowing additional attributes to be
+ specified on the association table.
- :ref:`composite_secondary_join` - a lesser-used pattern which in some
- cases can enable complex :func:`.relationship` SQL conditions
- to be used.
+ :ref:`composite_secondary_join` - a lesser-used pattern which
+ in some cases can enable complex :func:`.relationship` SQL
+ conditions to be used.
.. versionadded:: 0.9.2 :paramref:`~.relationship.secondary` works
more effectively when referring to a :class:`.Join` instance.
@@ -252,11 +257,13 @@ class RelationshipProperty(StrategizedProperty):
:param back_populates:
- Takes a string name and has the same meaning as :paramref:`~.relationship.backref`,
- except the complementing property is **not** created automatically,
- and instead must be configured explicitly on the other mapper. The
- complementing property should also indicate :paramref:`~.relationship.back_populates`
- to this relationship to ensure proper functioning.
+ Takes a string name and has the same meaning as
+ :paramref:`~.relationship.backref`, except the complementing
+ property is **not** created automatically, and instead must be
+ configured explicitly on the other mapper. The complementing
+ property should also indicate
+ :paramref:`~.relationship.back_populates` to this relationship to
+ ensure proper functioning.
.. seealso::
@@ -310,8 +317,9 @@ class RelationshipProperty(StrategizedProperty):
examples.
:param comparator_factory:
- a class which extends :class:`.RelationshipProperty.Comparator` which
- provides custom SQL clause generation for comparison operations.
+ a class which extends :class:`.RelationshipProperty.Comparator`
+ which provides custom SQL clause generation for comparison
+ operations.
.. seealso::
@@ -326,20 +334,21 @@ class RelationshipProperty(StrategizedProperty):
keyword to the innermost SELECT statement. When left as ``None``,
the DISTINCT keyword will be applied in those cases when the target
columns do not comprise the full primary key of the target table.
- When set to ``True``, the DISTINCT keyword is applied to the innermost
- SELECT unconditionally.
+ When set to ``True``, the DISTINCT keyword is applied to the
+ innermost SELECT unconditionally.
It may be desirable to set this flag to False when the DISTINCT is
reducing performance of the innermost subquery beyond that of what
duplicate innermost rows may be causing.
- .. versionadded:: 0.8.3 - :paramref:`~.relationship.distinct_target_key`
- allows the
+ .. versionadded:: 0.8.3 -
+ :paramref:`~.relationship.distinct_target_key` allows the
subquery eager loader to apply a DISTINCT modifier to the
innermost SELECT.
- .. versionchanged:: 0.9.0 - :paramref:`~.relationship.distinct_target_key`
- now defaults to ``None``, so that the feature enables itself automatically for
+ .. versionchanged:: 0.9.0 -
+ :paramref:`~.relationship.distinct_target_key` now defaults to
+ ``None``, so that the feature enables itself automatically for
those cases where the innermost query targets a non-unique
key.
@@ -388,8 +397,9 @@ class RelationshipProperty(StrategizedProperty):
.. versionchanged:: 0.8
A multiple-foreign key join ambiguity can be resolved by
- setting the :paramref:`~.relationship.foreign_keys` parameter alone, without the
- need to explicitly set :paramref:`~.relationship.primaryjoin` as well.
+ setting the :paramref:`~.relationship.foreign_keys`
+ parameter alone, without the need to explicitly set
+ :paramref:`~.relationship.primaryjoin` as well.
2. The :class:`.Table` being mapped does not actually have
:class:`.ForeignKey` or :class:`.ForeignKeyConstraint`
@@ -397,10 +407,11 @@ class RelationshipProperty(StrategizedProperty):
was reflected from a database that does not support foreign key
reflection (MySQL MyISAM).
- 3. The :paramref:`~.relationship.primaryjoin` argument is used to construct a non-standard
- join condition, which makes use of columns or expressions that do
- not normally refer to their "parent" column, such as a join condition
- expressed by a complex comparison using a SQL function.
+ 3. The :paramref:`~.relationship.primaryjoin` argument is used to
+ construct a non-standard join condition, which makes use of
+ columns or expressions that do not normally refer to their
+ "parent" column, such as a join condition expressed by a
+ complex comparison using a SQL function.
The :func:`.relationship` construct will raise informative
error messages that suggest the use of the
@@ -410,9 +421,10 @@ class RelationshipProperty(StrategizedProperty):
:paramref:`~.relationship.foreign_keys` parameter is usually
not needed.
- :paramref:`~.relationship.foreign_keys` may also be passed as a callable function
- which is evaluated at mapper initialization time, and may be passed as a
- Python-evaluable string when using Declarative.
+ :paramref:`~.relationship.foreign_keys` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
.. seealso::
@@ -420,14 +432,16 @@ class RelationshipProperty(StrategizedProperty):
:ref:`relationship_custom_foreign`
- :func:`.foreign` - allows direct annotation of the "foreign" columns
- within a :paramref:`~.relationship.primaryjoin` condition.
+ :func:`.foreign` - allows direct annotation of the "foreign"
+ columns within a :paramref:`~.relationship.primaryjoin` condition.
.. versionadded:: 0.8
The :func:`.foreign` annotation can also be applied
- directly to the :paramref:`~.relationship.primaryjoin` expression, which is an alternate,
- more specific system of describing which columns in a particular
- :paramref:`~.relationship.primaryjoin` should be considered "foreign".
+ directly to the :paramref:`~.relationship.primaryjoin`
+ expression, which is an alternate, more specific system of
+ describing which columns in a particular
+ :paramref:`~.relationship.primaryjoin` should be considered
+ "foreign".
:param info: Optional data dictionary which will be populated into the
:attr:`.MapperProperty.info` attribute of this object.
@@ -441,18 +455,19 @@ class RelationshipProperty(StrategizedProperty):
generally perform better than outer joins.
This flag can be set to ``True`` when the relationship references an
- object via many-to-one using local foreign keys that are not nullable,
- or when the reference is one-to-one or a collection that is guaranteed
- to have one or at least one entry.
+ object via many-to-one using local foreign keys that are not
+ nullable, or when the reference is one-to-one or a collection that
+ is guaranteed to have one or at least one entry.
- If the joined-eager load is chained onto an existing LEFT OUTER JOIN,
- ``innerjoin=True`` will be bypassed and the join will continue to
- chain as LEFT OUTER JOIN so that the results don't change. As an alternative,
- specify the value ``"nested"``. This will instead nest the join
- on the right side, e.g. using the form "a LEFT OUTER JOIN (b JOIN c)".
+ If the joined-eager load is chained onto an existing LEFT OUTER
+ JOIN, ``innerjoin=True`` will be bypassed and the join will continue
+ to chain as LEFT OUTER JOIN so that the results don't change. As an
+ alternative, specify the value ``"nested"``. This will instead nest
+ the join on the right side, e.g. using the form "a LEFT OUTER JOIN
+ (b JOIN c)".
- .. versionadded:: 0.9.4 Added ``innerjoin="nested"`` option to support
- nesting of eager "inner" joins.
+ .. versionadded:: 0.9.4 Added ``innerjoin="nested"`` option to
+ support nesting of eager "inner" joins.
.. seealso::
@@ -480,8 +495,8 @@ class RelationshipProperty(StrategizedProperty):
how the related items should be loaded. Default value is
``select``. Values include:
- * ``select`` - items should be loaded lazily when the property is first
- accessed, using a separate SELECT statement, or identity map
+ * ``select`` - items should be loaded lazily when the property is
+ first accessed, using a separate SELECT statement, or identity map
fetch for simple many-to-one references.
* ``immediate`` - items should be loaded as the parents are loaded,
@@ -494,8 +509,9 @@ class RelationshipProperty(StrategizedProperty):
:paramref:`~.relationship.innerjoin` parameter.
* ``subquery`` - items should be loaded "eagerly" as the parents are
- loaded, using one additional SQL statement, which issues a JOIN to a
- subquery of the original statement, for each collection requested.
+ loaded, using one additional SQL statement, which issues a JOIN to
+ a subquery of the original statement, for each collection
+ requested.
* ``noload`` - no loading should occur at any time. This is to
support "write-only" attributes, or attributes which are
@@ -524,35 +540,35 @@ class RelationshipProperty(StrategizedProperty):
Indicates loading behavior for transient or pending parent objects.
When set to ``True``, causes the lazy-loader to
- issue a query for a parent object that is not persistent, meaning it has
- never been flushed. This may take effect for a pending object when
- autoflush is disabled, or for a transient object that has been
+ issue a query for a parent object that is not persistent, meaning it
+ has never been flushed. This may take effect for a pending object
+ when autoflush is disabled, or for a transient object that has been
"attached" to a :class:`.Session` but is not part of its pending
collection.
- The :paramref:`~.relationship.load_on_pending` flag does not improve behavior
- when the ORM is used normally - object references should be constructed
- at the object level, not at the foreign key level, so that they
- are present in an ordinary way before a flush proceeds. This flag
- is not not intended for general use.
+ The :paramref:`~.relationship.load_on_pending` flag does not improve
+ behavior when the ORM is used normally - object references should be
+ constructed at the object level, not at the foreign key level, so
+ that they are present in an ordinary way before a flush proceeds.
+ This flag is not not intended for general use.
.. seealso::
- :meth:`.Session.enable_relationship_loading` - this method establishes
- "load on pending" behavior for the whole object, and also allows
- loading on objects that remain transient or detached.
+ :meth:`.Session.enable_relationship_loading` - this method
+ establishes "load on pending" behavior for the whole object, and
+ also allows loading on objects that remain transient or
+ detached.
:param order_by:
indicates the ordering that should be applied when loading these
- items. :paramref:`~.relationship.order_by` is expected to refer to one
- of the :class:`.Column`
- objects to which the target class is mapped, or
- the attribute itself bound to the target class which refers
- to the column.
+ items. :paramref:`~.relationship.order_by` is expected to refer to
+ one of the :class:`.Column` objects to which the target class is
+ mapped, or the attribute itself bound to the target class which
+ refers to the column.
- :paramref:`~.relationship.order_by` may also be passed as a callable function
- which is evaluated at mapper initialization time, and may be passed as a
- Python-evaluable string when using Declarative.
+ :paramref:`~.relationship.order_by` may also be passed as a callable
+ function which is evaluated at mapper initialization time, and may
+ be passed as a Python-evaluable string when using Declarative.
:param passive_deletes=False:
Indicates loading behavior during delete operations.
@@ -641,12 +657,13 @@ class RelationshipProperty(StrategizedProperty):
join of this child object against the parent object, or in a
many-to-many relationship the join of the primary object to the
association table. By default, this value is computed based on the
- foreign key relationships of the parent and child tables (or association
- table).
+ foreign key relationships of the parent and child tables (or
+ association table).
- :paramref:`~.relationship.primaryjoin` may also be passed as a callable function
- which is evaluated at mapper initialization time, and may be passed as a
- Python-evaluable string when using Declarative.
+ :paramref:`~.relationship.primaryjoin` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
.. seealso::
@@ -656,15 +673,16 @@ class RelationshipProperty(StrategizedProperty):
used for self-referential relationships, indicates the column or
list of columns that form the "remote side" of the relationship.
- :paramref:`.relationship.remote_side` may also be passed as a callable function
- which is evaluated at mapper initialization time, and may be passed as a
- Python-evaluable string when using Declarative.
+ :paramref:`.relationship.remote_side` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
.. versionchanged:: 0.8
The :func:`.remote` annotation can also be applied
- directly to the ``primaryjoin`` expression, which is an alternate,
- more specific system of describing which columns in a particular
- ``primaryjoin`` should be considered "remote".
+ directly to the ``primaryjoin`` expression, which is an
+ alternate, more specific system of describing which columns in a
+ particular ``primaryjoin`` should be considered "remote".
.. seealso::
@@ -672,8 +690,8 @@ class RelationshipProperty(StrategizedProperty):
:paramref:`~.relationship.remote_side`
is used to configure self-referential relationships.
- :func:`.remote` - an annotation function that accomplishes the same
- purpose as :paramref:`~.relationship.remote_side`, typically
+ :func:`.remote` - an annotation function that accomplishes the
+ same purpose as :paramref:`~.relationship.remote_side`, typically
when a custom :paramref:`~.relationship.primaryjoin` condition
is used.
@@ -686,18 +704,19 @@ class RelationshipProperty(StrategizedProperty):
.. seealso::
- :ref:`dynamic_relationship` - Introduction to "dynamic" relationship
- loaders.
+ :ref:`dynamic_relationship` - Introduction to "dynamic"
+ relationship loaders.
:param secondaryjoin:
a SQL expression that will be used as the join of
an association table to the child object. By default, this value is
- computed based on the foreign key relationships of the association and
- child tables.
+ computed based on the foreign key relationships of the association
+ and child tables.
- :paramref:`~.relationship.secondaryjoin` may also be passed as a callable function
- which is evaluated at mapper initialization time, and may be passed as a
- Python-evaluable string when using Declarative.
+ :paramref:`~.relationship.secondaryjoin` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
.. seealso::
@@ -710,9 +729,9 @@ class RelationshipProperty(StrategizedProperty):
should be treated either as one-to-one or one-to-many. Its usage
is optional, except for :func:`.relationship` constructs which
are many-to-one or many-to-many and also
- specify the ``delete-orphan`` cascade option. The :func:`.relationship`
- construct itself will raise an error instructing when this option
- is required.
+ specify the ``delete-orphan`` cascade option. The
+ :func:`.relationship` construct itself will raise an error
+ instructing when this option is required.
.. seealso::
@@ -727,33 +746,35 @@ class RelationshipProperty(StrategizedProperty):
of the relationship - one to many forms a list, many to one
forms a scalar, many to many is a list. If a scalar is desired
where normally a list would be present, such as a bi-directional
- one-to-one relationship, set :paramref:`~.relationship.uselist` to False.
+ one-to-one relationship, set :paramref:`~.relationship.uselist` to
+ False.
The :paramref:`~.relationship.uselist` flag is also available on an
- existing :func:`.relationship` construct as a read-only attribute, which
- can be used to determine if this :func:`.relationship` deals with
- collections or scalar attributes::
+ existing :func:`.relationship` construct as a read-only attribute,
+ which can be used to determine if this :func:`.relationship` deals
+ with collections or scalar attributes::
>>> User.addresses.property.uselist
True
.. seealso::
- :ref:`relationships_one_to_one` - Introduction to the "one to one"
- relationship pattern, which is typically when the
+ :ref:`relationships_one_to_one` - Introduction to the "one to
+ one" relationship pattern, which is typically when the
:paramref:`~.relationship.uselist` flag is needed.
:param viewonly=False:
when set to True, the relationship is used only for loading objects,
and not for any persistence operation. A :func:`.relationship`
which specifies :paramref:`~.relationship.viewonly` can work
- with a wider range of SQL operations within the :paramref:`~.relationship.primaryjoin`
- condition, including operations that feature the use of
- a variety of comparison operators as well as SQL functions such
- as :func:`~.sql.expression.cast`. The :paramref:`~.relationship.viewonly`
- flag is also of general use when defining any kind of :func:`~.relationship`
- that doesn't represent the full set of related objects, to prevent
- modifications of the collection from resulting in persistence operations.
+ with a wider range of SQL operations within the
+ :paramref:`~.relationship.primaryjoin` condition, including
+ operations that feature the use of a variety of comparison operators
+ as well as SQL functions such as :func:`~.sql.expression.cast`. The
+ :paramref:`~.relationship.viewonly` flag is also of general use when
+ defining any kind of :func:`~.relationship` that doesn't represent
+ the full set of related objects, to prevent modifications of the
+ collection from resulting in persistence operations.
"""
@@ -828,8 +849,8 @@ class RelationshipProperty(StrategizedProperty):
"""Produce boolean, comparison, and other operators for
:class:`.RelationshipProperty` attributes.
- See the documentation for :class:`.PropComparator` for a brief overview
- of ORM level operator definition.
+ See the documentation for :class:`.PropComparator` for a brief
+ overview of ORM level operator definition.
See also:
@@ -922,8 +943,9 @@ class RelationshipProperty(StrategizedProperty):
"""
raise NotImplementedError('in_() not yet supported for '
- 'relationships. For a simple many-to-one, use '
- 'in_() against the set of foreign key values.')
+ 'relationships. For a simple '
+ 'many-to-one, use in_() against '
+ 'the set of foreign key values.')
__hash__ = None
@@ -971,19 +993,21 @@ class RelationshipProperty(StrategizedProperty):
return _orm_annotate(self.property._optimized_compare(
None, adapt_source=self.adapter))
elif self.property.uselist:
- raise sa_exc.InvalidRequestError("Can't compare a colle"
- "ction to an object or collection; use "
- "contains() to test for membership.")
+ raise sa_exc.InvalidRequestError(
+ "Can't compare a collection to an object or collection; "
+ "use contains() to test for membership.")
else:
- return _orm_annotate(self.property._optimized_compare(other,
- adapt_source=self.adapter))
+ return _orm_annotate(
+ self.property._optimized_compare(
+ other, adapt_source=self.adapter))
def _criterion_exists(self, criterion=None, **kwargs):
if getattr(self, '_of_type', None):
info = inspect(self._of_type)
target_mapper, to_selectable, is_aliased_class = \
info.mapper, info.selectable, info.is_aliased_class
- if self.property._is_self_referential and not is_aliased_class:
+ if self.property._is_self_referential and not \
+ is_aliased_class:
to_selectable = to_selectable.alias()
single_crit = target_mapper._single_table_criterion
@@ -1002,9 +1026,10 @@ class RelationshipProperty(StrategizedProperty):
source_selectable = None
pj, sj, source, dest, secondary, target_adapter = \
- self.property._create_joins(dest_polymorphic=True,
- dest_selectable=to_selectable,
- source_selectable=source_selectable)
+ self.property._create_joins(
+ dest_polymorphic=True,
+ dest_selectable=to_selectable,
+ source_selectable=source_selectable)
for k in kwargs:
crit = getattr(self.property.mapper.class_, k) == kwargs[k]
@@ -1021,7 +1046,8 @@ class RelationshipProperty(StrategizedProperty):
else:
j = _orm_annotate(pj, exclude=self.property.remote_side)
- if criterion is not None and target_adapter and not is_aliased_class:
+ if criterion is not None and target_adapter and not \
+ is_aliased_class:
# limit this adapter to annotated only?
criterion = target_adapter.traverse(criterion)
@@ -1184,8 +1210,8 @@ class RelationshipProperty(StrategizedProperty):
raise sa_exc.InvalidRequestError(
"'contains' not implemented for scalar "
"attributes. Use ==")
- clause = self.property._optimized_compare(other,
- adapt_source=self.adapter)
+ clause = self.property._optimized_compare(
+ other, adapt_source=self.adapter)
if self.property.secondaryjoin is not None:
clause.negation_clause = \
@@ -1199,8 +1225,10 @@ class RelationshipProperty(StrategizedProperty):
def state_bindparam(x, state, col):
o = state.obj() # strong ref
- return sql.bindparam(x, unique=True, callable_=lambda:
- self.property.mapper._get_committed_attr_by_column(o, col))
+ return sql.bindparam(
+ x, unique=True, callable_=lambda:
+ self.property.mapper.
+ _get_committed_attr_by_column(o, col))
def adapt(col):
if self.adapter:
@@ -1270,9 +1298,10 @@ class RelationshipProperty(StrategizedProperty):
else:
return self._criterion_exists()
elif self.property.uselist:
- raise sa_exc.InvalidRequestError("Can't compare a collection"
- " to an object or collection; use "
- "contains() to test for membership.")
+ raise sa_exc.InvalidRequestError(
+ "Can't compare a collection"
+ " to an object or collection; use "
+ "contains() to test for membership.")
else:
return self.__negated_contains_or_equals(other)
@@ -1290,13 +1319,15 @@ class RelationshipProperty(StrategizedProperty):
if self.uselist:
return ~sql.exists([1], self.primaryjoin)
else:
- return self._optimized_compare(None,
- value_is_parent=value_is_parent,
- alias_secondary=alias_secondary)
+ return self._optimized_compare(
+ None,
+ value_is_parent=value_is_parent,
+ alias_secondary=alias_secondary)
else:
- return self._optimized_compare(value,
- value_is_parent=value_is_parent,
- alias_secondary=alias_secondary)
+ return self._optimized_compare(
+ value,
+ value_is_parent=value_is_parent,
+ alias_secondary=alias_secondary)
else:
return op(self.comparator, value)
@@ -1305,10 +1336,11 @@ class RelationshipProperty(StrategizedProperty):
alias_secondary=True):
if value is not None:
value = attributes.instance_state(value)
- return self._lazy_strategy.lazy_clause(value,
- reverse_direction=not value_is_parent,
- alias_secondary=alias_secondary,
- adapt_source=adapt_source)
+ return self._lazy_strategy.lazy_clause(
+ value,
+ reverse_direction=not value_is_parent,
+ alias_secondary=alias_secondary,
+ adapt_source=adapt_source)
def __str__(self):
return str(self.parent.class_.__name__) + "." + self.key
@@ -1326,7 +1358,7 @@ class RelationshipProperty(StrategizedProperty):
if (source_state, r) in _recursive:
return
- if not "merge" in self._cascade:
+ if "merge" not in self._cascade:
return
if self.key not in source_dict:
@@ -1363,8 +1395,8 @@ class RelationshipProperty(StrategizedProperty):
for c in dest_list:
coll.append_without_event(c)
else:
- dest_state.get_impl(self.key)._set_iterable(dest_state,
- dest_dict, dest_list)
+ dest_state.get_impl(self.key)._set_iterable(
+ dest_state, dest_dict, dest_list)
else:
current = source_dict[self.key]
if current is not None:
@@ -1404,7 +1436,7 @@ class RelationshipProperty(StrategizedProperty):
def cascade_iterator(self, type_, state, dict_,
visited_states, halt_on=None):
- #assert type_ in self._cascade
+ # assert type_ in self._cascade
# only actively lazy load on the 'delete' cascade
if type_ != 'delete' or self.passive_deletes:
@@ -1463,16 +1495,19 @@ class RelationshipProperty(StrategizedProperty):
other._reverse_property.add(self)
if not other.mapper.common_parent(self.parent):
- raise sa_exc.ArgumentError('reverse_property %r on '
- 'relationship %s references relationship %s, which '
- 'does not reference mapper %s' % (key, self, other,
- self.parent))
+ raise sa_exc.ArgumentError(
+ 'reverse_property %r on '
+ 'relationship %s references relationship %s, which '
+ 'does not reference mapper %s' %
+ (key, self, other, self.parent))
+
if self.direction in (ONETOMANY, MANYTOONE) and self.direction \
== other.direction:
- raise sa_exc.ArgumentError('%s and back-reference %s are '
- 'both of the same direction %r. Did you mean to '
- 'set remote_side on the many-to-one side ?'
- % (other, self, self.direction))
+ raise sa_exc.ArgumentError(
+ '%s and back-reference %s are '
+ 'both of the same direction %r. Did you mean to '
+ 'set remote_side on the many-to-one side ?' %
+ (other, self, self.direction))
@util.memoized_property
def mapper(self):
@@ -1494,9 +1529,10 @@ class RelationshipProperty(StrategizedProperty):
elif isinstance(self.argument, mapperlib.Mapper):
mapper_ = argument
else:
- raise sa_exc.ArgumentError("relationship '%s' expects "
- "a class or a mapper argument (received: %s)"
- % (self.key, type(argument)))
+ raise sa_exc.ArgumentError(
+ "relationship '%s' expects "
+ "a class or a mapper argument (received: %s)"
+ % (self.key, type(argument)))
return mapper_
@util.memoized_property
@@ -1601,17 +1637,17 @@ class RelationshipProperty(StrategizedProperty):
"""Test that this relationship is legal, warn about
inheritance conflicts."""
- if not self.is_primary() \
- and not mapperlib.class_mapper(
+ if not self.is_primary() and not mapperlib.class_mapper(
self.parent.class_,
configure=False).has_property(self.key):
- raise sa_exc.ArgumentError("Attempting to assign a new "
- "relationship '%s' to a non-primary mapper on "
- "class '%s'. New relationships can only be added "
- "to the primary mapper, i.e. the very first mapper "
- "created for class '%s' " % (self.key,
- self.parent.class_.__name__,
- self.parent.class_.__name__))
+ raise sa_exc.ArgumentError(
+ "Attempting to assign a new "
+ "relationship '%s' to a non-primary mapper on "
+ "class '%s'. New relationships can only be added "
+ "to the primary mapper, i.e. the very first mapper "
+ "created for class '%s' " %
+ (self.key, self.parent.class_.__name__,
+ self.parent.class_.__name__))
# check for conflicting relationship() on superclass
if not self.parent.concrete:
@@ -1700,10 +1736,11 @@ class RelationshipProperty(StrategizedProperty):
union(mapper.self_and_descendants)
for m in check:
if m.has_property(backref_key):
- raise sa_exc.ArgumentError("Error creating backref "
- "'%s' on relationship '%s': property of that "
- "name exists on mapper '%s'" % (backref_key,
- self, m))
+ raise sa_exc.ArgumentError(
+ "Error creating backref "
+ "'%s' on relationship '%s': property of that "
+ "name exists on mapper '%s'" %
+ (backref_key, self, m))
# determine primaryjoin/secondaryjoin for the
# backref. Use the one we had, so that
@@ -1713,13 +1750,16 @@ class RelationshipProperty(StrategizedProperty):
# for many to many, just switch primaryjoin/
# secondaryjoin. use the annotated
# pj/sj on the _join_condition.
- pj = kwargs.pop('primaryjoin',
- self._join_condition.secondaryjoin_minus_local)
- sj = kwargs.pop('secondaryjoin',
- self._join_condition.primaryjoin_minus_local)
+ pj = kwargs.pop(
+ 'primaryjoin',
+ self._join_condition.secondaryjoin_minus_local)
+ sj = kwargs.pop(
+ 'secondaryjoin',
+ self._join_condition.primaryjoin_minus_local)
else:
- pj = kwargs.pop('primaryjoin',
- self._join_condition.primaryjoin_reverse_remote)
+ pj = kwargs.pop(
+ 'primaryjoin',
+ self._join_condition.primaryjoin_reverse_remote)
sj = kwargs.pop('secondaryjoin', None)
if sj:
raise sa_exc.InvalidRequestError(
@@ -1936,24 +1976,24 @@ class JoinCondition(object):
)
except sa_exc.NoForeignKeysError:
if self.secondary is not None:
- raise sa_exc.NoForeignKeysError("Could not determine join "
- "condition between parent/child tables on "
- "relationship %s - there are no foreign keys "
- "linking these tables via secondary table '%s'. "
- "Ensure that referencing columns are associated "
- "with a ForeignKey or ForeignKeyConstraint, or "
- "specify 'primaryjoin' and 'secondaryjoin' "
- "expressions."
- % (self.prop, self.secondary))
+ raise sa_exc.NoForeignKeysError(
+ "Could not determine join "
+ "condition between parent/child tables on "
+ "relationship %s - there are no foreign keys "
+ "linking these tables via secondary table '%s'. "
+ "Ensure that referencing columns are associated "
+ "with a ForeignKey or ForeignKeyConstraint, or "
+ "specify 'primaryjoin' and 'secondaryjoin' "
+ "expressions." % (self.prop, self.secondary))
else:
- raise sa_exc.NoForeignKeysError("Could not determine join "
- "condition between parent/child tables on "
- "relationship %s - there are no foreign keys "
- "linking these tables. "
- "Ensure that referencing columns are associated "
- "with a ForeignKey or ForeignKeyConstraint, or "
- "specify a 'primaryjoin' expression."
- % self.prop)
+ raise sa_exc.NoForeignKeysError(
+ "Could not determine join "
+ "condition between parent/child tables on "
+ "relationship %s - there are no foreign keys "
+ "linking these tables. "
+ "Ensure that referencing columns are associated "
+ "with a ForeignKey or ForeignKeyConstraint, or "
+ "specify a 'primaryjoin' expression." % self.prop)
except sa_exc.AmbiguousForeignKeysError:
if self.secondary is not None:
raise sa_exc.AmbiguousForeignKeysError(
@@ -1984,7 +2024,8 @@ class JoinCondition(object):
@property
def secondaryjoin_minus_local(self):
- return _deep_deannotate(self.secondaryjoin, values=("local", "remote"))
+ return _deep_deannotate(self.secondaryjoin,
+ values=("local", "remote"))
@util.memoized_property
def primaryjoin_reverse_remote(self):
@@ -2262,11 +2303,10 @@ class JoinCondition(object):
"""
def repl(element):
if self.child_selectable.c.contains_column(element) and \
- (
- not self.parent_local_selectable.c.
- contains_column(element)
- or self.child_local_selectable.c.
- contains_column(element)):
+ (not self.parent_local_selectable.c.
+ contains_column(element) or
+ self.child_local_selectable.c.
+ contains_column(element)):
return element._annotate({"remote": True})
self.primaryjoin = visitors.replacement_traverse(
self.primaryjoin, {}, repl)
@@ -2309,15 +2349,15 @@ class JoinCondition(object):
def _check_remote_side(self):
if not self.local_remote_pairs:
- raise sa_exc.ArgumentError('Relationship %s could '
- 'not determine any unambiguous local/remote column '
- 'pairs based on join condition and remote_side '
- 'arguments. '
- 'Consider using the remote() annotation to '
- 'accurately mark those elements of the join '
- 'condition that are on the remote side of '
- 'the relationship.'
- % (self.prop, ))
+ raise sa_exc.ArgumentError(
+ 'Relationship %s could '
+ 'not determine any unambiguous local/remote column '
+ 'pairs based on join condition and remote_side '
+ 'arguments. '
+ 'Consider using the remote() annotation to '
+ 'accurately mark those elements of the join '
+ 'condition that are on the remote side of '
+ 'the relationship.' % (self.prop, ))
def _check_foreign_cols(self, join_condition, primary):
"""Check the foreign key columns collected and emit error
@@ -2446,10 +2486,11 @@ class JoinCondition(object):
elif manytoone_fk:
self.direction = MANYTOONE
else:
- raise sa_exc.ArgumentError("Can't determine relationship "
- "direction for relationship '%s' - foreign "
- "key columns are present in neither the parent "
- "nor the child's mapped tables" % self.prop)
+ raise sa_exc.ArgumentError(
+ "Can't determine relationship "
+ "direction for relationship '%s' - foreign "
+ "key columns are present in neither the parent "
+ "nor the child's mapped tables" % self.prop)
def _deannotate_pairs(self, collection):
"""provide deannotation for the various lists of
@@ -2586,15 +2627,16 @@ class JoinCondition(object):
if source_selectable is not None:
primary_aliasizer = \
ClauseAdapter(secondary).\
- chain(ClauseAdapter(source_selectable,
- equivalents=self.parent_equivalents))
+ chain(ClauseAdapter(
+ source_selectable,
+ equivalents=self.parent_equivalents))
secondaryjoin = \
secondary_aliasizer.traverse(secondaryjoin)
else:
- primary_aliasizer = ClauseAdapter(dest_selectable,
- exclude_fn=_ColInAnnotations(
- "local"),
- equivalents=self.child_equivalents)
+ primary_aliasizer = ClauseAdapter(
+ dest_selectable,
+ exclude_fn=_ColInAnnotations("local"),
+ equivalents=self.child_equivalents)
if source_selectable is not None:
primary_aliasizer.chain(
ClauseAdapter(source_selectable,