summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/query.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/query.py')
-rw-r--r--lib/sqlalchemy/orm/query.py171
1 files changed, 84 insertions, 87 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index a34fd882a..ca334e273 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -27,7 +27,7 @@ from . import (
from .util import (
AliasedClass, ORMAdapter, _entity_descriptor, PathRegistry,
_is_aliased_class, _is_mapped_class, _orm_columns,
- join as orm_join,with_parent, aliased
+ join as orm_join, with_parent, aliased
)
from .. import sql, util, log, exc as sa_exc, inspect, inspection, \
types as sqltypes
@@ -54,6 +54,7 @@ def _generative(*assertions):
_path_registry = PathRegistry.root
+
class Query(object):
"""ORM-level SQL construction object.
@@ -177,7 +178,6 @@ class Query(object):
self._from_obj_alias = sql_util.ColumnAdapter(
self._from_obj[0], equivs)
-
def _reset_polymorphic_adapter(self, mapper):
for m2 in mapper._with_polymorphic_mappers:
self._polymorphic_adapters.pop(m2, None)
@@ -274,7 +274,6 @@ class Query(object):
return self._select_from_entity or \
self._entity_zero().entity_zero
-
@property
def _mapper_entities(self):
# TODO: this is wrong, its hardcoded to "primary entity" when
@@ -325,7 +324,6 @@ class Query(object):
)
return self._entity_zero()
-
def __all_equivs(self):
equivs = {}
for ent in self._mapper_entities:
@@ -540,10 +538,9 @@ class Query(object):
return self.enable_eagerloads(False).statement.label(name)
-
def as_scalar(self):
- """Return the full SELECT statement represented by this :class:`.Query`, converted
- to a scalar subquery.
+ """Return the full SELECT statement represented by this
+ :class:`.Query`, converted to a scalar subquery.
Analogous to :meth:`sqlalchemy.sql.SelectBaseMixin.as_scalar`.
@@ -618,7 +615,8 @@ class Query(object):
@property
def whereclause(self):
- """A readonly attribute which returns the current WHERE criterion for this Query.
+ """A readonly attribute which returns the current WHERE criterion for
+ this Query.
This returned value is a SQL expression construct, or ``None`` if no
criterion has been established.
@@ -648,11 +646,11 @@ class Query(object):
:meth:`.Query.with_polymorphic` applies transformations
to the "main" mapped class represented by this :class:`.Query`.
The "main" mapped class here means the :class:`.Query`
- object's first argument is a full class, i.e. ``session.query(SomeClass)``.
- These transformations allow additional tables to be present
- in the FROM clause so that columns for a joined-inheritance
- subclass are available in the query, both for the purposes
- of load-time efficiency as well as the ability to use
+ object's first argument is a full class, i.e.
+ ``session.query(SomeClass)``. These transformations allow additional
+ tables to be present in the FROM clause so that columns for a
+ joined-inheritance subclass are available in the query, both for the
+ purposes of load-time efficiency as well as the ability to use
these columns at query time.
See the documentation section :ref:`with_polymorphic` for
@@ -783,7 +781,8 @@ class Query(object):
not mapper.always_refresh and \
self._lockmode is None:
- instance = loading.get_from_identity(self.session, key, attributes.PASSIVE_OFF)
+ instance = loading.get_from_identity(
+ self.session, key, attributes.PASSIVE_OFF)
if instance is not None:
# reject calls for id in identity map but class
# mismatch.
@@ -980,8 +979,8 @@ class Query(object):
@_generative()
def with_entities(self, *entities):
- """Return a new :class:`.Query` replacing the SELECT list with the given
- entities.
+ """Return a new :class:`.Query` replacing the SELECT list with the
+ given entities.
e.g.::
@@ -1006,7 +1005,6 @@ class Query(object):
"""
self._set_entities(entities)
-
@_generative()
def add_columns(self, *column):
"""Add one or more column expressions to the list
@@ -1024,13 +1022,13 @@ class Query(object):
":meth:`.add_column` is superseded by :meth:`.add_columns`",
False)
def add_column(self, column):
- """Add a column expression to the list of result columns to be returned.
+ """Add a column expression to the list of result columns to be
+ returned.
Pending deprecation: :meth:`.add_column` will be superseded by
:meth:`.add_columns`.
"""
-
return self.add_columns(column)
def options(self, *args):
@@ -1340,9 +1338,8 @@ class Query(object):
"""
-
return self._from_selectable(
- expression.union(*([self]+ list(q))))
+ expression.union(*([self] + list(q))))
def union_all(self, *q):
"""Produce a UNION ALL of this Query against one or more queries.
@@ -1352,7 +1349,7 @@ class Query(object):
"""
return self._from_selectable(
- expression.union_all(*([self]+ list(q)))
+ expression.union_all(*([self] + list(q)))
)
def intersect(self, *q):
@@ -1363,7 +1360,7 @@ class Query(object):
"""
return self._from_selectable(
- expression.intersect(*([self]+ list(q)))
+ expression.intersect(*([self] + list(q)))
)
def intersect_all(self, *q):
@@ -1374,7 +1371,7 @@ class Query(object):
"""
return self._from_selectable(
- expression.intersect_all(*([self]+ list(q)))
+ expression.intersect_all(*([self] + list(q)))
)
def except_(self, *q):
@@ -1385,7 +1382,7 @@ class Query(object):
"""
return self._from_selectable(
- expression.except_(*([self]+ list(q)))
+ expression.except_(*([self] + list(q)))
)
def except_all(self, *q):
@@ -1396,7 +1393,7 @@ class Query(object):
"""
return self._from_selectable(
- expression.except_all(*([self]+ list(q)))
+ expression.except_all(*([self] + list(q)))
)
def join(self, *props, **kwargs):
@@ -1422,9 +1419,9 @@ class Query(object):
In the above example we refer to ``User.addresses`` as passed to
:meth:`~.Query.join` as the *on clause*, that is, it indicates
how the "ON" portion of the JOIN should be constructed. For a
- single-entity query such as the one above (i.e. we start by selecting only from
- ``User`` and nothing else), the relationship can also be specified by its
- string name::
+ single-entity query such as the one above (i.e. we start by selecting
+ only from ``User`` and nothing else), the relationship can also be
+ specified by its string name::
q = session.query(User).join("addresses")
@@ -1434,8 +1431,9 @@ class Query(object):
q = session.query(User).join("orders", "items", "keywords")
- The above would be shorthand for three separate calls to :meth:`~.Query.join`,
- each using an explicit attribute to indicate the source entity::
+ The above would be shorthand for three separate calls to
+ :meth:`~.Query.join`, each using an explicit attribute to indicate
+ the source entity::
q = session.query(User).\\
join(User.orders).\\
@@ -1511,25 +1509,26 @@ class Query(object):
There is a lot of flexibility in what the "target" can be when using
:meth:`~.Query.join`. As noted previously, it also accepts
- :class:`.Table` constructs and other selectables such as :func:`.alias`
- and :func:`.select` constructs, with either the one or two-argument forms::
+ :class:`.Table` constructs and other selectables such as
+ :func:`.alias` and :func:`.select` constructs, with either the one
+ or two-argument forms::
addresses_q = select([Address.user_id]).\\
- where(Address.email_address.endswith("@bar.com")).\\
- alias()
+ where(Address.email_address.endswith("@bar.com")).\\
+ alias()
q = session.query(User).\\
join(addresses_q, addresses_q.c.user_id==User.id)
:meth:`~.Query.join` also features the ability to *adapt* a
- :meth:`~sqlalchemy.orm.relationship` -driven ON clause to the target selectable.
- Below we construct a JOIN from ``User`` to a subquery against ``Address``, allowing
- the relationship denoted by ``User.addresses`` to *adapt* itself
- to the altered target::
+ :meth:`~sqlalchemy.orm.relationship` -driven ON clause to the target
+ selectable. Below we construct a JOIN from ``User`` to a subquery
+ against ``Address``, allowing the relationship denoted by
+ ``User.addresses`` to *adapt* itself to the altered target::
address_subq = session.query(Address).\\
- filter(Address.email_address == 'ed@foo.com').\\
- subquery()
+ filter(Address.email_address == 'ed@foo.com').\\
+ subquery()
q = session.query(User).join(address_subq, User.addresses)
@@ -1811,7 +1810,7 @@ class Query(object):
if not create_aliases and prop:
self._update_joinpoint({
'_joinpoint_entity': right,
- 'prev':((left, right, prop.key), self._joinpoint)
+ 'prev': ((left, right, prop.key), self._joinpoint)
})
else:
self._joinpoint = {
@@ -2051,7 +2050,7 @@ class Query(object):
if item == -1:
return list(self)[-1]
else:
- return list(self[item:item+1])[0]
+ return list(self[item:item + 1])[0]
@_generative(_no_statement_condition)
def slice(self, start, stop):
@@ -2261,8 +2260,8 @@ class Query(object):
def _execute_and_instances(self, querycontext):
conn = self._connection_from_session(
- mapper = self._mapper_zero_or_none(),
- clause = querycontext.statement,
+ mapper=self._mapper_zero_or_none(),
+ clause=querycontext.statement,
close_with_result=True)
result = conn.execute(querycontext.statement, self._params)
@@ -2330,20 +2329,20 @@ class Query(object):
return loading.instances(self, cursor, context)
-
def merge_result(self, iterator, load=True):
"""Merge a result into this :class:`.Query` object's Session.
- Given an iterator returned by a :class:`.Query` of the same structure as this
- one, return an identical iterator of results, with all mapped
- instances merged into the session using :meth:`.Session.merge`. This is an
- optimized method which will merge all mapped instances, preserving the
- structure of the result rows and unmapped columns with less method
- overhead than that of calling :meth:`.Session.merge` explicitly for each
- value.
+ Given an iterator returned by a :class:`.Query` of the same structure
+ as this one, return an identical iterator of results, with all mapped
+ instances merged into the session using :meth:`.Session.merge`. This
+ is an optimized method which will merge all mapped instances,
+ preserving the structure of the result rows and unmapped columns with
+ less method overhead than that of calling :meth:`.Session.merge`
+ explicitly for each value.
The structure of the results is determined based on the column list of
- this :class:`.Query` - if these do not correspond, unchecked errors will occur.
+ this :class:`.Query` - if these do not correspond, unchecked errors
+ will occur.
The 'load' argument is the same as that of :meth:`.Session.merge`.
@@ -2359,12 +2358,12 @@ class Query(object):
@property
def _select_args(self):
return {
- 'limit':self._limit,
- 'offset':self._offset,
- 'distinct':self._distinct,
- 'prefixes':self._prefixes,
- 'group_by':self._group_by or None,
- 'having':self._having
+ 'limit': self._limit,
+ 'offset': self._offset,
+ 'distinct': self._distinct,
+ 'prefixes': self._prefixes,
+ 'group_by': self._group_by or None,
+ 'having': self._having
}
@property
@@ -2435,8 +2434,8 @@ class Query(object):
removed from the session. Matched objects are removed from the
session.
- ``'evaluate'`` - Evaluate the query's criteria in Python straight on
- the objects in the session. If evaluation of the criteria isn't
+ ``'evaluate'`` - Evaluate the query's criteria in Python straight
+ on the objects in the session. If evaluation of the criteria isn't
implemented, an error is raised. In that case you probably
want to use the 'fetch' strategy as a fallback.
@@ -2487,8 +2486,8 @@ class Query(object):
objects that are matched by the update query. The updated
attributes are expired on matched objects.
- ``'evaluate'`` - Evaluate the Query's criteria in Python straight on
- the objects in the session. If evaluation of the criteria isn't
+ ``'evaluate'`` - Evaluate the Query's criteria in Python straight
+ on the objects in the session. If evaluation of the criteria isn't
implemented, an exception is raised.
The expression evaluator currently doesn't account for differing
@@ -2522,7 +2521,6 @@ class Query(object):
update_op.exec_()
return update_op.rowcount
-
_lockmode_lookup = {
'read': 'read',
'read_nowait': 'read_nowait',
@@ -2708,6 +2706,7 @@ class Query(object):
inspection._self_inspects(Query)
+
class _QueryEntity(object):
"""represent an entity column returned within a Query result."""
@@ -2726,6 +2725,7 @@ class _QueryEntity(object):
q.__dict__ = self.__dict__.copy()
return q
+
class _MapperEntity(_QueryEntity):
"""mapper/class/AliasedClass entity"""
@@ -2739,7 +2739,7 @@ class _MapperEntity(_QueryEntity):
def setup_entity(self, ext_info, aliased_adapter):
self.mapper = ext_info.mapper
self.aliased_adapter = aliased_adapter
- self.selectable = ext_info.selectable
+ self.selectable = ext_info.selectable
self.is_aliased_class = ext_info.is_aliased_class
self._with_polymorphic = ext_info.with_polymorphic_mappers
self._polymorphic_discriminator = \
@@ -2829,28 +2829,27 @@ class _MapperEntity(_QueryEntity):
# require row aliasing unconditionally.
if not adapter and self.mapper._requires_row_aliasing:
adapter = sql_util.ColumnAdapter(
- self.selectable,
- self.mapper._equivalent_columns)
+ self.selectable,
+ self.mapper._equivalent_columns)
if self.primary_entity:
_instance = loading.instance_processor(
- self.mapper,
- context,
- self.path,
- adapter,
- only_load_props=query._only_load_props,
- refresh_state=context.refresh_state,
- polymorphic_discriminator=
- self._polymorphic_discriminator
+ self.mapper,
+ context,
+ self.path,
+ adapter,
+ only_load_props=query._only_load_props,
+ refresh_state=context.refresh_state,
+ polymorphic_discriminator=self._polymorphic_discriminator
)
else:
_instance = loading.instance_processor(
- self.mapper,
- context,
- self.path,
- adapter,
- polymorphic_discriminator=
- self._polymorphic_discriminator)
+ self.mapper,
+ context,
+ self.path,
+ adapter,
+ polymorphic_discriminator=self._polymorphic_discriminator
+ )
return _instance, self._label_name
@@ -2902,6 +2901,7 @@ class _MapperEntity(_QueryEntity):
def __str__(self):
return str(self.mapper)
+
class _ColumnEntity(_QueryEntity):
"""Column/expression based entity."""
@@ -2931,7 +2931,6 @@ class _ColumnEntity(_QueryEntity):
if c is not column:
return
-
if not isinstance(column, sql.ColumnElement):
raise sa_exc.InvalidRequestError(
"SQL expression, column, or mapped entity "
@@ -2981,7 +2980,6 @@ class _ColumnEntity(_QueryEntity):
else:
self.entity_zero = None
-
@property
def entity_zero_or_selectable(self):
if self.entity_zero is not None:
@@ -2995,7 +2993,6 @@ class _ColumnEntity(_QueryEntity):
def type(self):
return self.column.type
-
def adapt_to_selectable(self, query, sel):
c = _ColumnEntity(query, sel.corresponding_column(self.column))
c._label_name = self._label_name
@@ -3040,8 +3037,10 @@ class _ColumnEntity(_QueryEntity):
def __str__(self):
return str(self.column)
+
log.class_logger(Query)
+
class QueryContext(object):
multi_row_eager_loaders = False
adapter = None
@@ -3089,5 +3088,3 @@ class AliasOption(interfaces.MapperOption):
else:
alias = self.alias
query._from_obj_alias = sql_util.ColumnAdapter(alias)
-
-