"""
Functional constructs for ORM configuration.
-See the SQLAlchemy object relational tutorial and mapper configuration
+See the SQLAlchemy object relational tutorial and mapper configuration
documentation for an overview of how this module is used.
"""
def scoped_session(session_factory, scopefunc=None):
"""Provides thread-local management of Sessions.
-
+
This is a front-end function to the [sqlalchemy.orm.scoping#ScopedSession]
class.
To instantiate a Session object which is part of the scoped
context, instantiate normally::
-
+
session = Session()
-
+
Most session methods are available as classmethods from
the scoped session::
-
+
Session.commit()
Session.close()
-
+
To map classes so that new instances are saved in the current
Session automatically, as well as to provide session-aware
class attributes such as "query", use the `mapper` classmethod
from the scoped session::
-
+
mapper = Session.mapper
mapper(Class, table, ...)
"""
-
+
return ScopedSession(session_factory, scopefunc=scopefunc)
-
+
def create_session(bind=None, **kwargs):
"""create a new [sqlalchemy.orm.session#Session].
-
+
The session by default does not begin a transaction, and requires that
flush() be called explicitly in order to persist results to the database.
-
- It is recommended to use the [sqlalchemy.orm#sessionmaker()] function
+
+ It is recommended to use the [sqlalchemy.orm#sessionmaker()] function
instead of create_session().
"""
kwargs.setdefault('autoflush', False)
kwargs.setdefault('transactional', False)
return _Session(bind=bind, **kwargs)
-
+
def relation(argument, secondary=None, **kwargs):
"""Provide a relationship of a primary Mapper to a secondary Mapper.
- This corresponds to a parent-child or associative table relationship.
+ This corresponds to a parent-child or associative table relationship.
The constructed class is an instance of [sqlalchemy.orm.properties#PropertyLoader].
argument
\**kwargs follow:
association
- Deprecated; as of version 0.3.0 the association keyword is synonomous
+ Deprecated; as of version 0.3.0 the association keyword is synonymous
with applying the "all, delete-orphan" cascade to a "one-to-many"
relationship. SA can now automatically reconcile a "delete" and
"insert" operation of two objects with the same "identity" in a flush()
operation into a single "update" statement, which is the pattern that
- "association" used to indicate.
-
+ "association" used to indicate.
+
backref
indicates the name of a property to be placed on the related mapper's
class that will handle this relationship in the other direction,
including synchronizing the object attributes on both sides of the
relation. Can also point to a ``backref()`` construct for more
- configurability.
-
+ configurability.
+
cascade
a string list of cascade rules which determines how persistence
- operations should be "cascaded" from parent to child.
-
+ operations should be "cascaded" from parent to child.
+
collection_class
a class or function that returns a new list-holding object. will be
- used in place of a plain list for storing elements.
-
+ used in place of a plain list for storing elements.
+
foreign_keys
a list of columns which are to be used as "foreign key" columns.
this parameter should be used in conjunction with explicit
deep eagerload joins should be constructed on a self-referring
or cyclical relationship. The number counts how many times
the same Mapper shall be present in the loading condition along
- a particular join branch. When left at its default of ``None``,
- eager loads will automatically stop chaining joins when they encounter
+ a particular join branch. When left at its default of ``None``,
+ eager loads will automatically stop chaining joins when they encounter
a mapper which is already higher up in the chain.
-
+
lazy=(True|False|None|'dynamic')
specifies how the related items should be loaded. Values include:
-
+
True - items should be loaded lazily when the property is first
- accessed.
-
- False - items should be loaded "eagerly" in the same query as that
+ accessed.
+
+ False - items should be loaded "eagerly" in the same query as that
of the parent, using a JOIN or LEFT OUTER JOIN.
-
+
None - no loading should occur at any time. This is to support
- "write-only" attrbitutes, or attributes which are populated in
+ "write-only" attributes, or attributes which are populated in
some manner specific to the application.
-
+
'dynamic' - a ``DynaLoader`` will be attached, which returns a
``Query`` object for all read operations. The dynamic-
collection supports only ``append()`` and ``remove()``
- for write operations; changes to the dynamic property
- will not be visible until the data is flushed to the
- database.
+ for write operations; changes to the dynamic property
+ will not be visible until the data is flushed to the
+ database.
order_by
indicates the ordering that should be applied when loading these items.
passive_deletes=False
- Indicates loading behavior during delete operations.
-
+ Indicates loading behavior during delete operations.
+
A value of True indicates that unloaded child items should not be loaded
during a delete operation on the parent. Normally, when a parent
item is deleted, all child items are loaded so that they can either be
Marking this flag as True usually implies an ON DELETE <CASCADE|SET NULL>
rule is in place which will handle updating/deleting child rows on the
database side.
-
+
Additionally, setting the flag to the string value 'all' will disable
the "nulling out" of the child foreign keys, when there is no delete or
delete-orphan cascade enabled. This is typically used when a triggering
or error raise scenario is in place on the database side. Note that
the foreign key attributes on in-session child objects will not be changed
after a flush occurs so this is a very special use-case setting.
-
+
passive_updates=True
Indicates loading and INSERT/UPDATE/DELETE behavior when the source
- of a foreign key value changes (i.e. an "on update" cascade), which are
- typically the primary key columns of the source row.
-
+ of a foreign key value changes (i.e. an "on update" cascade), which
+ are typically the primary key columns of the source row.
+
When True, it is assumed that ON UPDATE CASCADE is configured on the
- foreign key in the database, and that the database will handle propagation of an
- UPDATE from a source column to dependent rows. Note that with databases
- which enforce referential integrity (ie. Postgres, MySQL with InnoDB tables),
- ON UPDATE CASCADE is required for this operation. The relation() will
- update the value of the attribute on related items which are locally present
- in the session during a flush.
-
- When False, it is assumed that the database does not enforce referential
- integrity and will not be issuing its own CASCADE operation for an update.
- The relation() will issue the appropriate UPDATE statements to the database
- in response to the change of a referenced key, and items locally present
- in the session during a flush will also be refreshed.
-
- This flag should probably be set to False if primary key changes are expected
- and the database in use doesn't support CASCADE (i.e. SQLite, MySQL MyISAM tables).
-
+ foreign key in the database, and that the database will handle
+ propagation of an UPDATE from a source column to dependent rows.
+ Note that with databases which enforce referential integrity
+ (i.e. Postgres, MySQL with InnoDB tables), ON UPDATE CASCADE is
+ required for this operation. The relation() will update the value
+ of the attribute on related items which are locally present in the
+ session during a flush.
+
+ When False, it is assumed that the database does not enforce
+ referential integrity and will not be issuing its own CASCADE
+ operation for an update. The relation() will issue the appropriate
+ UPDATE statements to the database in response to the change of a
+ referenced key, and items locally present in the session during a
+ flush will also be refreshed.
+
+ This flag should probably be set to False if primary key changes are
+ expected and the database in use doesn't support CASCADE
+ (i.e. SQLite, MySQL MyISAM tables).
+
post_update
this indicates that the relationship should be handled by a second
- UPDATE statement after an INSERT or before a DELETE. Currently, it also
- will issue an UPDATE after the instance was UPDATEd as well, although
- this technically should be improved. This flag is used to handle saving
- bi-directional dependencies between two individual rows (i.e. each row
- references the other), where it would otherwise be impossible to INSERT
- or DELETE both rows fully since one row exists before the other. Use
- this flag when a particular mapping arrangement will incur two rows
- that are dependent on each other, such as a table that has a
- one-to-many relationship to a set of child rows, and also has a column
- that references a single child row within that list (i.e. both tables
- contain a foreign key to each other). If a ``flush()`` operation returns
- an error that a "cyclical dependency" was detected, this is a cue that
- you might want to use ``post_update`` to "break" the cycle.
+ UPDATE statement after an INSERT or before a DELETE. Currently, it
+ also will issue an UPDATE after the instance was UPDATEd as well,
+ although this technically should be improved. This flag is used to
+ handle saving bi-directional dependencies between two individual
+ rows (i.e. each row references the other), where it would otherwise
+ be impossible to INSERT or DELETE both rows fully since one row
+ exists before the other. Use this flag when a particular mapping
+ arrangement will incur two rows that are dependent on each other,
+ such as a table that has a one-to-many relationship to a set of
+ child rows, and also has a column that references a single child row
+ within that list (i.e. both tables contain a foreign key to each
+ other). If a ``flush()`` operation returns an error that a "cyclical
+ dependency" was detected, this is a cue that you might want to use
+ ``post_update`` to "break" the cycle.
primaryjoin
a ClauseElement that will be used as the primary join of this child
private=False
deprecated. setting ``private=True`` is the equivalent of setting
``cascade="all, delete-orphan"``, and indicates the lifecycle of child
- objects should be contained within that of the parent.
+ objects should be contained within that of the parent.
remote_side
used for self-referential relationships, indicates the column or list
- of columns that form the "remote side" of the relationship.
+ of columns that form the "remote side" of the relationship.
secondaryjoin
a ClauseElement that will be used as the join of an association table
return PropertyLoader(argument, secondary=secondary, **kwargs)
-def dynamic_loader(argument, secondary=None, primaryjoin=None, secondaryjoin=None, entity_name=None,
+def dynamic_loader(argument, secondary=None, primaryjoin=None, secondaryjoin=None, entity_name=None,
foreign_keys=None, backref=None, post_update=False, cascade=None, remote_side=None, enable_typechecks=True,
passive_deletes=False):
"""construct a dynamically-loading mapper property.
-
+
This property is similar to relation(), except read operations
- return an active Query object, which reads from the database in all
+ return an active Query object, which reads from the database in all
cases. Items may be appended to the attribute via append(), or
removed via remove(); changes will be persisted
to the database during a flush(). However, no other list mutation
operations are available.
-
+
A subset of arguments available to relation() are available here.
"""
from sqlalchemy.orm.strategies import DynaLoader
-
- return PropertyLoader(argument, secondary=secondary, primaryjoin=primaryjoin,
- secondaryjoin=secondaryjoin, entity_name=entity_name, foreign_keys=foreign_keys, backref=backref,
- post_update=post_update, cascade=cascade, remote_side=remote_side, enable_typechecks=enable_typechecks,
+
+ return PropertyLoader(argument, secondary=secondary, primaryjoin=primaryjoin,
+ secondaryjoin=secondaryjoin, entity_name=entity_name, foreign_keys=foreign_keys, backref=backref,
+ post_update=post_update, cascade=cascade, remote_side=remote_side, enable_typechecks=enable_typechecks,
passive_deletes=passive_deletes,
strategy_class=DynaLoader)
the mapper's selectable; examples include SQL expressions, functions,
and scalar SELECT queries.
- Columns that arent present in the mapper's selectable won't be persisted
+ Columns that aren't present in the mapper's selectable won't be persisted
by the mapper and are effectively "read-only" attributes.
\*cols
list of Column objects to be mapped.
-
+
group
a group name for this property when marked as deferred.
-
+
deferred
when True, the column property is "deferred", meaning that
it does not load immediately, and is instead loaded when the
- attribute is first accessed on an instance. See also
+ attribute is first accessed on an instance. See also
[sqlalchemy.orm#deferred()].
"""
-
+
return ColumnProperty(*args, **kwargs)
def composite(class_, *cols, **kwargs):
"""Return a composite column-based property for use with a Mapper.
-
+
This is very much like a column-based property except the given class
is used to represent "composite" values composed of one or more columns.
... composite(Point, mytable.c.x, mytable.c.y) ...
Arguments are:
-
+
class\_
The "composite type" class.
-
+
\*cols
List of Column objects to be mapped.
-
+
group
A group name for this property when marked as deferred.
-
+
deferred
When True, the column property is "deferred", meaning that
it does not load immediately, and is instead loaded when the
- attribute is first accessed on an instance. See also
+ attribute is first accessed on an instance. See also
[sqlalchemy.orm#deferred()].
-
+
comparator
An optional instance of [sqlalchemy.orm#PropComparator] which
provides SQL expression generation functions for this composite
type.
"""
-
+
return CompositeProperty(class_, *cols, **kwargs)
-
+
def backref(name, **kwargs):
"""Create a BackRef object with explicit arguments, which are the same arguments one
overwrite all data within object instances that already
exist within the session, erasing any in-memory changes with
whatever information was loaded from the database. Usage
- of this flag is highly discouraged; as an alternative,
+ of this flag is highly discouraged; as an alternative,
see the method `populate_existing()` on [sqlalchemy.orm.query#Query].
allow_column_override
inherit_foreign_keys
when inherit_condition is used and the condition contains no
- ForeignKey columns, specify the "foreign" columns of the join
+ ForeignKey columns, specify the "foreign" columns of the join
condition in this list. else leave as None.
-
+
order_by
A single ``Column`` or list of ``Columns`` for which
selection operations should use as the default ordering for
hierarchy.
_polymorphic_map
- Used internally to propigate the full map of polymorphic
+ Used internally to propagate the full map of polymorphic
identifiers to surrogate mappers.
polymorphic_identity
this mapper.
polymorphic_fetch
- specifies how subclasses mapped through joined-table
- inheritance will be fetched. options are 'union',
- 'select', and 'deferred'. if the select_table argument
+ specifies how subclasses mapped through joined-table
+ inheritance will be fetched. options are 'union',
+ 'select', and 'deferred'. if the select_table argument
is present, defaults to 'union', otherwise defaults to
'select'.
can be overridden here.
select_table
- A [sqlalchemy.schema#Table] or any [sqlalchemy.sql#Selectable]
- which will be used to select instances of this mapper's class.
- usually used to provide polymorphic loading among several
+ A [sqlalchemy.schema#Table] or any [sqlalchemy.sql#Selectable]
+ which will be used to select instances of this mapper's class.
+ usually used to provide polymorphic loading among several
classes in an inheritance hierarchy.
version_id_col
"""Set up `name` as a synonym to another mapped property.
Used with the ``properties`` dictionary sent to [sqlalchemy.orm#mapper()].
-
+
Any existing attributes on the class which map the key name sent
- to the ``properties`` dictionary will be used by the synonym to
+ to the ``properties`` dictionary will be used by the synonym to
provide instance-attribute behavior (that is, any Python property object,
- provided by the ``property`` builtin or providing a ``__get__()``,
+ provided by the ``property`` builtin or providing a ``__get__()``,
``__set__()`` and ``__del__()`` method). If no name exists for the key,
the ``synonym()`` creates a default getter/setter object automatically
and applies it to the class.
-
+
`name` refers to the name of the existing mapped property, which
can be any other ``MapperProperty`` including column-based
properties and relations.
-
- if `map_column` is ``True``, an additional ``ColumnProperty``
- is created on the mapper automatically, using the synonym's
- name as the keyname of the property, and the keyname of this ``synonym()``
- as the name of the column to map. For example, if a table has a column
- named ``status``::
-
+
+ If `map_column` is ``True``, an additional ``ColumnProperty`` is created
+ on the mapper automatically, using the synonym's name as the keyname of
+ the property, and the keyname of this ``synonym()`` as the name of the
+ column to map. For example, if a table has a column named ``status``::
+
class MyClass(object):
def _get_status(self):
return self._status
def _set_status(self, value):
self._status = value
status = property(_get_status, _set_status)
-
+
mapper(MyClass, sometable, properties={
"status":synonym("_status", map_column=True)
})
-
- The column named ``status`` will be mapped to the attribute named ``_status``,
- and the ``status`` attribute on ``MyClass`` will be used to proxy access to the
- column-based attribute.
-
- The `proxy` keyword argument is deprecated and currently does nothing; synonyms
- now always establish an attribute getter/setter funciton if one is not already available.
+
+ The column named ``status`` will be mapped to the attribute named
+ ``_status``, and the ``status`` attribute on ``MyClass`` will be used to
+ proxy access to the column-based attribute.
+
+ The `proxy` keyword argument is deprecated and currently does nothing;
+ synonyms now always establish an attribute getter/setter function if one
+ is not already available.
"""
return SynonymProperty(name, map_column=map_column)
mapper.dispose()
finally:
mapperlib._COMPILE_MUTEX.release()
-
+
def extension(ext):
"""Return a ``MapperOption`` that will insert the given
``MapperExtension`` to the beginning of the list of extensions
def eagerload_all(name, mapper=None):
"""Return a ``MapperOption`` that will convert all properties along the given dot-separated path into an eager load.
-
+
For example, this::
query.options(eagerload_all('orders.items.keywords'))...
-
+
will set all of 'orders', 'orders.items', and 'orders.items.keywords'
to load in one eager load.
def fetchmode(name, type):
return strategies.FetchModeOption(name, type)
-
+
def noload(name):
"""Return a ``MapperOption`` that will convert the property of the
given name into a non-load.
Used when feeding SQL result sets directly into
``query.instances()``. Also bundles an ``EagerLazyOption`` to
- turn on eager loading in case it isnt already.
+ turn on eager loading in case it isn't already.
`alias` is the string name of an alias, **or** an ``sql.Alias``
object, which represents the aliased columns in the query. This
return strategies.DeferredOption(name, defer=False)
def undefer_group(name):
- """Return a ``MapperOption`` that will convert the given
+ """Return a ``MapperOption`` that will convert the given
group of deferred column properties into a non-deferred (regular column) load.
Used with ``query.options()``.
"""
return strategies.UndeferGroupOption(name)
-
specified in terms of generic decorator recipes, but are instead hand-tooled for
increased efficiency. The targeted decorators occasionally implement
adapter-like behavior, such as mapping bulk-set methods (``extend``, ``update``,
-``__setslice``, etc.) into the series of atomic mutation events that the ORM
+``__setslice__``, etc.) into the series of atomic mutation events that the ORM
requires.
The targeted decorators are used internally for automatic instrumentation of
def fire_pre_remove_event(self, initiator=None):
"""Notify that an entity is about to be removed from the collection.
-
- Only called if the entity cannot be removed after calling
+
+ Only called if the entity cannot be removed after calling
fire_remove_event().
"""
-
+
self.attr.fire_pre_remove_event(self.owner_state, initiator=initiator)
-
+
def __getstate__(self):
return { 'key': self.attr.key,
'owner_state': self.owner_state,
executor = getattr(collection, '_sa_adapter', None)
if executor:
getattr(executor, 'fire_pre_remove_event')(_sa_initiator)
-
+
def _list_decorators():
"""Hand-turned instrumentation wrappers that can decorate any list-like
class."""
which can be end-user subclassed to add event-based functionality
to mappers. The remainder of this module is generally private to the
ORM.
-
"""
+
from sqlalchemy import util, logging, exceptions
from sqlalchemy.sql import expression
from itertools import chain
class_mapper = None
__all__ = ['EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS', 'MapperExtension',
- 'MapperProperty', 'PropComparator', 'StrategizedProperty',
- 'build_path', 'MapperOption',
- 'ExtensionOption', 'PropertyOption',
+ 'MapperProperty', 'PropComparator', 'StrategizedProperty',
+ 'build_path', 'MapperOption',
+ 'ExtensionOption', 'PropertyOption',
'AttributeExtension', 'StrategizedOption', 'LoaderStrategy' ]
EXT_CONTINUE = EXT_PASS = object()
class MapperExtension(object):
"""Base implementation for customizing Mapper behavior.
- For each method in MapperExtension, returning a result of
- EXT_CONTINUE will allow processing to continue to the next
- MapperExtension in line or use the default functionality if there
- are no other extensions.
-
- Returning EXT_STOP will halt processing of further extensions
- handling that method. Some methods such as ``load`` have other
- return requirements, see the individual documentation for details.
- Other than these exception cases, any return value other than
- EXT_CONTINUE or EXT_STOP will be interpreted as equivalent to
- EXT_STOP.
-
- EXT_PASS is a synonym for EXT_CONTINUE and is provided for
- backward compatibility.
+ For each method in MapperExtension, returning a result of EXT_CONTINUE
+ will allow processing to continue to the next MapperExtension in line or
+ use the default functionality if there are no other extensions.
+
+ Returning EXT_STOP will halt processing of further extensions handling
+ that method. Some methods such as ``load`` have other return
+ requirements, see the individual documentation for details. Other than
+ these exception cases, any return value other than EXT_CONTINUE or
+ EXT_STOP will be interpreted as equivalent to EXT_STOP.
+
+ EXT_PASS is a synonym for EXT_CONTINUE and is provided for backward
+ compatibility.
"""
-
+
def instrument_class(self, mapper, class_):
return EXT_CONTINUE
-
+
def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
return EXT_CONTINUE
The return value of this method is used as the result of
``query.get_by()`` if the value is anything other than
EXT_CONTINUE.
-
+
DEPRECATED.
"""
The return value of this method is used as the result of
``query.select_by()`` if the value is anything other than
EXT_CONTINUE.
-
+
DEPRECATED.
"""
The return value of this method is used as the result of
``query.select()`` if the value is anything other than
EXT_CONTINUE.
-
+
DEPRECATED.
"""
"""Receive a row when a new object instance is about to be
created from that row.
- The method can choose to create the instance itself, or it can
- return EXT_CONTINUE to indicate normal object creation should take
- place.
+ The method can choose to create the instance itself, or it can return
+ EXT_CONTINUE to indicate normal object creation should take place.
mapper
The mapper doing the operation
class\_
The class we are mapping.
-
+
return value
A new object instance, or EXT_CONTINUE
"""
This is a good place to set up primary key values and such
that aren't handled otherwise.
- Column-based attributes can be modified within this method which will
- result in the new value being inserted. However *no* changes to the overall
+ Column-based attributes can be modified within this method which will
+ result in the new value being inserted. However *no* changes to the overall
flush plan can be made; this means any collection modification or
save() operations which occur within this method will not take effect
until the next flush call.
-
+
"""
return EXT_CONTINUE
def before_update(self, mapper, connection, instance):
"""Receive an object instance before that instance is UPDATEed.
-
- Note that this method is called for all instances that are marked as
- "dirty", even those which have no net changes to their column-based
+
+ Note that this method is called for all instances that are marked as
+ "dirty", even those which have no net changes to their column-based
attributes. An object is marked as dirty when any of its column-based
- attributes have a "set attribute" operation called or when any of its
+ attributes have a "set attribute" operation called or when any of its
collections are modified. If, at update time, no column-based attributes
have any net changes, no UPDATE statement will be issued. This means
that an instance being sent to before_update is *not* a guarantee that
here).
To detect if the column-based attributes on the object have net changes,
- and will therefore generate an UPDATE statement, use
+ and will therefore generate an UPDATE statement, use
``object_session(instance).is_modified(instance, include_collections=False)``.
-
- Column-based attributes can be modified within this method which will
- result in their being updated. However *no* changes to the overall
+
+ Column-based attributes can be modified within this method which will
+ result in their being updated. However *no* changes to the overall
flush plan can be made; this means any collection modification or
save() operations which occur within this method will not take effect
until the next flush call.
-
+
"""
return EXT_CONTINUE
def before_delete(self, mapper, connection, instance):
"""Receive an object instance before that instance is DELETEed.
-
- Note that *no* changes to the overall
+
+ Note that *no* changes to the overall
flush plan can be made here; this means any collection modification,
- save() or delete() operations which occur within this method will
+ save() or delete() operations which occur within this method will
not take effect until the next flush call.
-
+
"""
return EXT_CONTINUE
def setup(self, querycontext, **kwargs):
"""Called by Query for the purposes of constructing a SQL statement.
-
+
Each MapperProperty associated with the target mapper processes the
statement referenced by the query context, adding columns and/or
criterion as appropriate.
pass
def create_row_processor(self, selectcontext, mapper, row):
- """return a 3-tuple consiting of two row processing functions and an instance post-processing function.
-
+ """Return a 3-tuple consiting of two row processing functions and an instance post-processing function.
+
Input arguments are the query.SelectionContext and the *first*
- applicable row of a result set obtained within query.Query.instances(), called
- only the first time a particular mapper's populate_instance() method is invoked for the
- overall result.
-
- The settings contained within the SelectionContext as well as the columns present
- in the row (which will be the same columns present in all rows) are used to determine
- the presence and behavior of the returned callables. The callables will then be used to process
- all rows and to post-process all instances, respectively.
-
- callables are of the following form::
-
+ applicable row of a result set obtained within
+ query.Query.instances(), called only the first time a particular
+ mapper's populate_instance() method is invoked for the overall result.
+
+ The settings contained within the SelectionContext as well as the
+ columns present in the row (which will be the same columns present in
+ all rows) are used to determine the presence and behavior of the
+ returned callables. The callables will then be used to process all
+ rows and to post-process all instances, respectively.
+
+ Callables are of the following form::
+
def new_execute(instance, row, **flags):
- # process incoming instance and given row. the instance is "new" and
- # was just created upon receipt of this row.
- # flags is a dictionary containing at least the following attributes:
- # isnew - indicates if the instance was newly created as a result of reading this row
+ # process incoming instance and given row. the instance is
+ # "new" and was just created upon receipt of this row.
+ # flags is a dictionary containing at least the following
+ # attributes:
+ # isnew - indicates if the instance was newly created as a
+ # result of reading this row
# instancekey - identity key of the instance
# optional attribute:
- # ispostselect - indicates if this row resulted from a 'post' select of additional tables/columns
+ # ispostselect - indicates if this row resulted from a
+ # 'post' select of additional tables/columns
def existing_execute(instance, row, **flags):
- # process incoming instance and given row. the instance is "existing" and
- # was created based on a previous row.
-
+ # process incoming instance and given row. the instance is
+ # "existing" and was created based on a previous row.
+
def post_execute(instance, **flags):
- # process instance after all result rows have been processed. this
- # function should be used to issue additional selections in order to
- # eagerly load additional properties.
-
+ # process instance after all result rows have been processed.
+ # this function should be used to issue additional selections
+ # in order to eagerly load additional properties.
+
return (new_execute, existing_execute, post_execute)
-
- either of the three tuples can be ``None`` in which case no function is called.
-
+
+ Either of the three tuples can be ``None`` in which case no function
+ is called.
"""
-
+
raise NotImplementedError()
def cascade_iterator(self, type, object, recursive=None, halt_on=None):
- """iterate through instances related to the given instance along
+ """Iterate through instances related to the given instance along
a particular 'cascade' path, starting with this MapperProperty.
-
- see PropertyLoader for the related instance implementation.
+
+ See PropertyLoader for the related instance implementation.
"""
-
+
return iter([])
def get_criterion(self, query, key, value):
is a value to be matched. This is only picked up by
``PropertyLoaders``.
- This is called by a ``Query``'s ``join_by`` method to
- formulate a set of key/value pairs into a ``WHERE`` criterion
- that spans multiple tables if needed.
+ This is called by a ``Query``'s ``join_by`` method to formulate a set
+ of key/value pairs into a ``WHERE`` criterion that spans multiple
+ tables if needed.
"""
return None
def do_init(self):
"""Perform subclass-specific initialization steps.
-
- This is a *template* method called by the
+
+ This is a *template* method called by the
``MapperProperty`` object's init() method."""
-
+
pass
def register_dependencies(self, *args, **kwargs):
this ``MapperProperty`` to the given value, which may be a
column value or an instance. 'operator' is an operator from
the operators module, or from sql.Comparator.
-
+
By default uses the PropComparator attached to this MapperProperty
under the attribute name "comparator".
"""
class PropComparator(expression.ColumnOperators):
"""defines comparison operations for MapperProperty objects"""
-
+
def expression_element(self):
return self.clause_element()
-
+
def contains_op(a, b):
return a.contains(b)
contains_op = staticmethod(contains_op)
-
+
def any_op(a, b, **kwargs):
return a.any(b, **kwargs)
any_op = staticmethod(any_op)
-
+
def has_op(a, b, **kwargs):
return a.has(b, **kwargs)
has_op = staticmethod(has_op)
-
+
def __init__(self, prop):
self.prop = prop
def contains(self, other):
- """return true if this collection contains other"""
+ """Return true if this collection contains other"""
return self.operate(PropComparator.contains_op, other)
def any(self, criterion=None, **kwargs):
- """return true if this collection contains any member that meets the given criterion.
-
- criterion
- an optional ClauseElement formulated against the member class' table or attributes.
-
- \**kwargs
- key/value pairs corresponding to member class attribute names which will be compared
- via equality to the corresponding values.
+ """Return true if this collection contains any member that meets the given criterion.
+
+ criterion
+ an optional ClauseElement formulated against the member class' table
+ or attributes.
+
+ \**kwargs
+ key/value pairs corresponding to member class attribute names which
+ will be compared via equality to the corresponding values.
"""
return self.operate(PropComparator.any_op, criterion, **kwargs)
-
+
def has(self, criterion=None, **kwargs):
- """return true if this element references a member which meets the given criterion.
-
-
+ """Return true if this element references a member which meets the given criterion.
+
criterion
- an optional ClauseElement formulated against the member class' table or attributes.
-
+ an optional ClauseElement formulated against the member class' table
+ or attributes.
+
\**kwargs
- key/value pairs corresponding to member class attribute names which will be compared
- via equality to the corresponding values.
+ key/value pairs corresponding to member class attribute names which
+ will be compared via equality to the corresponding values.
"""
return self.operate(PropComparator.has_op, criterion, **kwargs)
-
+
class StrategizedProperty(MapperProperty):
"""A MapperProperty which uses selectable strategies to affect
loading behavior.
(mapper.class_, mapper.entity_name, key)
for mapper, key in [(path[i], path[i+1]) for i in range(0, len(path)-1, 2)]
]
-
+
def deserialize_path(path):
if path is None:
return None
def process_query(self, query):
pass
-
+
def process_query_conditionally(self, query):
"""same as process_query(), except that this option may not apply
- to the given query.
-
- Used when secondary loaders resend existing options to a new
+ to the given query.
+
+ Used when secondary loaders resend existing options to a new
Query."""
self.process_query(query)
class ExtensionOption(MapperOption):
"""a MapperOption that applies a MapperExtension to a query operation."""
-
+
def __init__(self, ext):
self.ext = ext
def __init__(self, key, mapper=None):
self.key = key
self.mapper = mapper
-
+
def process_query(self, query):
self._process(query, True)
-
+
def process_query_conditionally(self, query):
self._process(query, False)
-
+
def _process(self, query, raiseerr):
if self._should_log_debug:
self.logger.debug("applying option to Query, property key '%s'" % self.key)
path = None
l = []
current_path = list(query._current_path)
-
+
if self.mapper:
global class_mapper
if class_mapper is None:
def is_chained(self):
return False
-
+
def process_query_property(self, query, paths):
if self.is_chained():
for path in paths:
list of selected columns, *eager loading* properties may add
``LEFT OUTER JOIN`` clauses to the statement.
- * it processes the ``SelectionContext`` at row-processing time. This
+ * it processes the ``SelectionContext`` at row-processing time. This
includes straight population of attributes corresponding to rows,
setting instance-level lazyloader callables on newly
- constructed instances, and appending child items to scalar/collection
+ constructed instances, and appending child items to scalar/collection
attributes in response to eagerly-loaded relations.
"""
def init(self):
self.parent = self.parent_property.parent
self.key = self.parent_property.key
-
+
def init_class_attribute(self):
pass
pass
def create_row_processor(self, selectcontext, mapper, row):
- """return row processing functions which fulfill the contract specified
+ """Return row processing functions which fulfill the contract specified
by MapperProperty.create_row_processor.
-
-
- StrategizedProperty delegates its create_row_processor method
- directly to this method.
+
+ StrategizedProperty delegates its create_row_processor method directly
+ to this method.
"""
raise NotImplementedError()
unit which associates a class with a database table.
This is a semi-private module; the main configurational API of the ORM is
-avaiable in [sqlalchemy.orm#].
+available in [sqlalchemy.orm#].
"""
import weakref
self._row_translators = {}
self._dependency_processors = []
self._clause_adapter = None
-
+
# our 'polymorphic identity', a string name that when located in a result set row
# indicates this Mapper should be used to construct the object instance for that row.
self.polymorphic_identity = polymorphic_identity
if self.version_id_col is None:
self.version_id_col = self.inherits.version_id_col
-
+
for mapper in self.iterate_to_root():
if hasattr(mapper, '_genned_equivalent_columns'):
del mapper._genned_equivalent_columns
-
+
if self.order_by is False:
self.order_by = self.inherits.order_by
self.polymorphic_map = self.inherits.polymorphic_map
if len(primary_key) == 0:
raise exceptions.ArgumentError("Mapper %s could not assemble any primary key columns for mapped table '%s'" % (self, self.mapped_table.description))
-
+
self.primary_key = primary_key
self.__log("Identified primary key columns: " + str(primary_key))
self._genned_equivalent_columns = self.__get_equivalent_columns()
return self._genned_equivalent_columns
_equivalent_columns = property(_equivalent_columns)
-
+
class _CompileOnAttr(PropComparator):
"""placeholder class attribute which fires mapper compilation on access"""
self.__surrogate_mapper = Mapper(self.class_, self.select_table, non_primary=True, _polymorphic_map=self.polymorphic_map, polymorphic_on=_corresponding_column_or_error(self.select_table, self.polymorphic_on), primary_key=self.primary_key_argument)
adapter = sqlutil.ClauseAdapter(self.select_table, equivalents=self.__surrogate_mapper._equivalent_columns)
-
+
if self.order_by:
order_by = [expression._literal_as_text(o) for o in util.to_list(self.order_by) or []]
order_by = adapter.copy_and_process(order_by)
self.__surrogate_mapper.order_by=order_by
-
+
if self._init_properties is not None:
for key, prop in self._init_properties.iteritems():
if expression.is_column(prop):
self.__surrogate_mapper.add_property(key, _corresponding_column_or_error(self.select_table, prop))
elif (isinstance(prop, list) and expression.is_column(prop[0])):
self.__surrogate_mapper.add_property(key, [_corresponding_column_or_error(self.select_table, c) for c in prop])
-
+
self.__surrogate_mapper._clause_adapter = adapter
def _compile_class(self):
self.add_property(key, value)
def add_property(self, key, prop):
- """Add an indiviual MapperProperty to this mapper.
+ """Add an individual MapperProperty to this mapper.
If the mapper has not been compiled yet, just adds the
property to the initial properties dictionary sent to the
try:
identitykey = refresh_instance.dict['_instance_key']
except KeyError:
- # super-rare condition; a refresh is being called
- # on a non-instance-key instance; this is meant to only
+ # super-rare condition; a refresh is being called
+ # on a non-instance-key instance; this is meant to only
# occur wihtin a flush()
identitykey = self._identity_key_from_state(refresh_instance)
else:
session = mapper.get_session()
except exceptions.InvalidRequestError:
raise exceptions.UnboundExecutionError("Instance %s is not bound to a Session, and no contextual session is established; attribute refresh operation cannot proceed" % (instance.__class__))
-
+
state = instance._state
if '_instance_key' in state.dict:
identity_key = state.dict['_instance_key']
self._current_path = ()
self._only_load_props = None
self._refresh_instance = None
-
+
self._adapter = self.select_mapper._clause_adapter
-
+
def _no_criterion(self, meth):
q = self._clone()
instance.
\**kwargs
- all extra keyword arguments are propigated to the constructor of
+ all extra keyword arguments are propagated to the constructor of
Query.
"""
Query, and subsequent elements matching columns or entities which were
specified via add_column or add_entity.
- When adding entities to the result, its generally desireable to add
+ When adding entities to the result, its generally desirable to add
limiting criterion to the query which can associate the primary entity
of this Query along with the additional entities. The Query selects
from all tables with no joining criterion by default.
class for this Query, and subsequent elements matching columns or
entities which were specified via add_column or add_entity.
- When adding columns to the result, its generally desireable to add
+ When adding columns to the result, its generally desirable to add
limiting criterion to the query which can associate the primary entity
of this Query along with the additional columns, if the column is
based on a table or selectable that is not the primary mapped
q._params = q._params.copy()
q._params.update(kwargs)
return q
-
+
def filter(self, criterion):
"""apply the given filtering criterion to the query and return the newly resulting ``Query``
if self._adapter is not None:
criterion = self._adapter.traverse(criterion)
-
+
q = self._no_statement("filter")
if q._criterion is not None:
q._criterion = q._criterion & criterion
currenttables = self._get_joinable_tables()
# determine if generated joins need to be aliased on the left
- # hand side.
+ # hand side.
if self._adapter and not self._aliases: # at the beginning of a join, look at leftmost adapter
adapt_against = self._adapter.selectable
elif start.select_table is not start.mapped_table: # in the middle of a join, look for a polymorphic mapper
raise exceptions.InvalidRequestError("Selectable '%s' is not derived from '%s'" % (use_selectable.description, prop.mapper.mapped_table.description))
if not isinstance(use_selectable, expression.Alias):
use_selectable = use_selectable.alias()
-
+
if prop._is_self_referential() and not create_aliases and not use_selectable:
raise exceptions.InvalidRequestError("Self-referential query on '%s' property requires create_aliases=True argument." % str(prop))
else:
if use_selectable:
alias = mapperutil.PropertyAliasedClauses(prop,
- prop.primary_join_against(mapper, adapt_against),
+ prop.primary_join_against(mapper, adapt_against),
None,
alias,
alias=use_selectable
clause = clause.join(alias.alias, crit, isouter=outerjoin)
elif create_aliases:
alias = mapperutil.PropertyAliasedClauses(prop,
- prop.primary_join_against(mapper, adapt_against),
+ prop.primary_join_against(mapper, adapt_against),
None,
alias
)
return q
def having(self, criterion):
- """apply a HAVING criterion to the quer and return the newly resulting ``Query``."""
+ """apply a HAVING criterion to the query and return the newly resulting ``Query``."""
if isinstance(criterion, basestring):
criterion = sql.text(criterion)
* a 2-tuple containing one of the above, combined with a selectable
which derives from the properties' mapped table
* a list (not a tuple) containing a combination of any of the above.
-
+
e.g.::
-
+
session.query(Company).join('employees')
session.query(Company).join(['employees', 'tasks'])
session.query(Houses).join([Colonials.rooms, Room.closets])
* a 2-tuple containing one of the above, combined with a selectable
which derives from the properties' mapped table
* a list (not a tuple) containing a combination of any of the above.
-
+
e.g.::
-
+
session.query(Company).outerjoin('employees')
session.query(Company).outerjoin(['employees', 'tasks'])
session.query(Houses).outerjoin([Colonials.rooms, Room.closets])
session.query(Company).join([('employees', people.join(engineers)), Engineer.computers])
-
+
"""
return self._join(prop, id=id, outerjoin=True, aliased=aliased, from_joinpoint=from_joinpoint)
q._from_obj = clause
q._joinpoint = mapper
q._aliases = aliases
-
+
if aliases:
q._adapter = sql_util.ClauseAdapter(aliases.alias).copy_and_chain(q._adapter)
else:
adapter = None
adapter = self._adapter
-
+
# TODO: mappers added via add_entity(), adapt their queries also,
# if those mappers are polymorphic
context.primary_columns.append(c)
statement = sql.select(context.primary_columns + context.secondary_columns, whereclause, from_obj=from_obj, use_labels=True, for_update=for_update, order_by=util.to_list(order_by), **self._select_args())
-
+
if context.eager_joins:
if adapter:
context.eager_joins = adapter.traverse(context.eager_joins)
return self._alias_ids[alias_id]
except KeyError:
raise exceptions.InvalidRequestError("Query has no alias identified by '%s'" % alias_id)
-
+
if isinstance(m, type):
m = mapper.class_mapper(m)
if isinstance(m, mapper.Mapper):