summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/__init__.py63
-rw-r--r--lib/sqlalchemy/orm/deprecated_interfaces.py4
-rw-r--r--lib/sqlalchemy/orm/events.py9
-rw-r--r--lib/sqlalchemy/orm/mapper.py2
-rw-r--r--lib/sqlalchemy/orm/properties.py5
-rw-r--r--lib/sqlalchemy/orm/query.py5
-rw-r--r--lib/sqlalchemy/orm/strategies.py7
7 files changed, 66 insertions, 29 deletions
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 0f8a7d95c..f7145c433 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -204,6 +204,16 @@ def relationship(argument, secondary=None, **kwargs):
generally mutually exclusive with the use of the *secondary*
keyword argument.
+ :param active_history=False:
+ When ``True``, indicates that the "previous" value for a
+ many-to-one reference should be loaded when replaced, if
+ not already loaded. Normally, history tracking logic for
+ simple many-to-ones only needs to be aware of the "new"
+ value in order to perform a flush. This flag is available
+ for applications that make use of
+ :func:`.attributes.get_history` which also need to know
+ the "previous" value of the attribute. (New in 0.6.6)
+
:param backref:
indicates the string name of a property to be placed on the related
mapper's class that will handle this relationship in the other
@@ -572,7 +582,7 @@ def column_property(*args, **kwargs):
"""Provide a column-level property for use with a Mapper.
Column-based properties can normally be applied to the mapper's
- ``properties`` dictionary using the ``schema.Column`` element directly.
+ ``properties`` dictionary using the :class:`.Column` element directly.
Use this function when the given column is not directly present within the
mapper's selectable; examples include SQL expressions, functions, and
scalar SELECT queries.
@@ -583,6 +593,16 @@ def column_property(*args, **kwargs):
:param \*cols:
list of Column objects to be mapped.
+ :param active_history=False:
+ When ``True``, indicates that the "previous" value for a
+ scalar attribute should be loaded when replaced, if not
+ already loaded. Normally, history tracking logic for
+ simple non-primary-key scalar values only needs to be
+ aware of the "new" value in order to perform a flush. This
+ flag is available for applications that make use of
+ :func:`.attributes.get_history` which also need to know
+ the "previous" value of the attribute. (new in 0.6.6)
+
:param comparator_factory: a class which extends
:class:`.ColumnProperty.Comparator` which provides custom SQL clause
generation for comparison operations.
@@ -684,7 +704,7 @@ def mapper(class_, local_table=None, *args, **params):
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, see the method
- `populate_existing()` on :class:`~sqlalchemy.orm.query.Query`.
+ :meth:`.Query.populate_existing`.
:param allow_null_pks: This flag is deprecated - this is stated as
allow_partial_pks which defaults to True.
@@ -693,7 +713,7 @@ def mapper(class_, local_table=None, *args, **params):
composite primary key with some NULL values should be considered as
possibly existing within the database. This affects whether a
mapper will assign an incoming row to an existing identity, as well
- as if session.merge() will check the database first for a
+ as if :meth:`.Session.merge` will check the database first for a
particular primary key value. A "partial primary key" can occur if
one has mapped to an OUTER JOIN, for example.
@@ -702,13 +722,14 @@ def mapper(class_, local_table=None, *args, **params):
that an instance will be fully saved before saving the next
instance, which includes inserting/updating all table rows
corresponding to the entity as well as calling all
- :class:`MapperExtension` methods corresponding to the save
+ :class:`.MapperExtension` methods corresponding to the save
operation.
:param column_prefix: A string which will be prepended to the `key`
- name of all Columns when creating column-based properties from the
- given Table. Does not affect explicitly specified column-based
- properties
+ name of all :class:`.Column` objects when creating
+ column-based properties from the
+ given :class:`.Table`. Does not affect explicitly specified
+ column-based properties
:param concrete: If True, indicates this mapper should use concrete
table inheritance with its parent mapper.
@@ -735,13 +756,13 @@ def mapper(class_, local_table=None, *args, **params):
present in the mapped table but not named or present in this list
will not be automatically mapped. See also "exclude_properties".
- :param inherits: Another :class:`~sqlalchemy.orm.Mapper` for which
- this :class:`~sqlalchemy.orm.Mapper` will have an inheritance
+ :param inherits: Another :class:`.Mapper` for which
+ this :class:`.Mapper` will have an inheritance
relationship with.
:param inherit_condition: For joined table inheritance, a SQL
expression (constructed
- :class:`~sqlalchemy.expression.sql.ClauseElement`) which will
+ :class:`.ClauseElement`) which will
define how the two tables are joined; defaults to a natural join
between the two tables.
@@ -753,7 +774,7 @@ def mapper(class_, local_table=None, *args, **params):
the selection of instances, not their persistence. Any number of
non_primary mappers may be created for a particular class.
- :param order_by: A single :class:`Column` or list of :class:`Column`
+ :param order_by: A single :class:`.Column` or list of :class:`.Column`
objects for which selection operations should use as the default
ordering for entities. Defaults to the OID/ROWID of the table if
any, or the first primary key column of the table.
@@ -788,7 +809,7 @@ def mapper(class_, local_table=None, *args, **params):
this flag.
:param polymorphic_on: Used with mappers in an inheritance
- relationship, a ``Column`` which will identify the class/mapper
+ relationship, a :class:`.Column` which will identify the class/mapper
combination to be used with a particular row. Requires the
``polymorphic_identity`` value to be set for all mappers in the
inheritance hierarchy. The column specified by ``polymorphic_on``
@@ -798,23 +819,23 @@ def mapper(class_, local_table=None, *args, **params):
argument.
:param polymorphic_identity: A value which will be stored in the
- Column denoted by polymorphic_on, corresponding to the *class
- identity* of this mapper.
+ Column denoted by polymorphic_on, corresponding to the class
+ identity of this mapper.
:param properties: A dictionary mapping the string names of object
attributes to ``MapperProperty`` instances, which define the
persistence behavior of that attribute. Note that the columns in
the mapped table are automatically converted into
- ``ColumnProperty`` instances based on the `key` property of each
- ``Column`` (although they can be overridden using this dictionary).
+ ``ColumnProperty`` instances based on the ``key`` property of each
+ :class:`.Column` (although they can be overridden using this dictionary).
- :param primary_key: A list of ``Column`` objects which define the
- *primary key* to be used against this mapper's selectable unit.
- This is normally simply the primary key of the `local_table`, but
+ :param primary_key: A list of :class:`.Column` objects which define the
+ primary key to be used against this mapper's selectable unit.
+ This is normally simply the primary key of the ``local_table``, but
can be overridden here.
- :param version_id_col: A ``Column`` which must have an integer type
- that will be used to keep a running *version id* of mapped entities
+ :param version_id_col: A :class:`.Column` which must have an integer type
+ that will be used to keep a running version id of mapped entities
in the database. this is used during save operations to ensure that
no other thread or process has updated the instance during the
lifetime of the entity, else a :class:`StaleDataError` exception is
diff --git a/lib/sqlalchemy/orm/deprecated_interfaces.py b/lib/sqlalchemy/orm/deprecated_interfaces.py
index 3e4f268d0..52193b149 100644
--- a/lib/sqlalchemy/orm/deprecated_interfaces.py
+++ b/lib/sqlalchemy/orm/deprecated_interfaces.py
@@ -526,6 +526,10 @@ class AttributeExtension(object):
active_history = True
"""indicates that the set() method would like to receive the 'old' value,
even if it means firing lazy callables.
+
+ Note that ``active_history`` can also be set directly via
+ :func:`.column_property` and :func:`.relationship`.
+
"""
@classmethod
diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py
index fc8cab2ed..b610408b7 100644
--- a/lib/sqlalchemy/orm/events.py
+++ b/lib/sqlalchemy/orm/events.py
@@ -783,9 +783,12 @@ class AttributeEvents(event.Events):
Several modifiers are available to the :func:`~.event.listen` function.
:param active_history=False: When True, indicates that the
- "on_set" event would like to receive the "old" value
- being replaced unconditionally, even if this requires
- firing off database loads.
+ "on_set" event would like to receive the "old" value being
+ replaced unconditionally, even if this requires firing off
+ database loads. Note that ``active_history`` can also be
+ set directly via :func:`.column_property` and
+ :func:`.relationship`.
+
:param propagate=False: When True, the listener function will
be established not just for the class attribute given, but
for attributes of the same name on all current subclasses
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 75ba0b5c0..accb7c4be 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -104,7 +104,7 @@ class Mapper(object):
self.class_manager = None
- self.primary_key_argument = primary_key
+ self.primary_key_argument = util.to_list(primary_key)
self.non_primary = non_primary
if order_by is not False:
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index feee041ce..edfb861f4 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -60,6 +60,7 @@ class ColumnProperty(StrategizedProperty):
self.__class__.Comparator)
self.descriptor = kwargs.pop('descriptor', None)
self.extension = kwargs.pop('extension', None)
+ self.active_history = kwargs.pop('active_history', False)
if 'doc' in kwargs:
self.doc = kwargs.pop('doc')
@@ -114,6 +115,7 @@ class ColumnProperty(StrategizedProperty):
return ColumnProperty(
deferred=self.deferred,
group=self.group,
+ active_history=self.active_history,
*self.columns)
def _getattr(self, state, dict_, column, passive=False):
@@ -184,6 +186,7 @@ class CompositeProperty(ColumnProperty):
deferred=self.deferred,
group=self.group,
composite_class=self.composite_class,
+ active_history=self.active_history,
*self.columns)
def do_init(self):
@@ -444,6 +447,7 @@ class RelationshipProperty(StrategizedProperty):
comparator_factory=None,
single_parent=False, innerjoin=False,
doc=None,
+ active_history=False,
cascade_backrefs=True,
load_on_pending=False,
strategy_class=None, _local_remote_pairs=None,
@@ -469,6 +473,7 @@ class RelationshipProperty(StrategizedProperty):
self.query_class = query_class
self.innerjoin = innerjoin
self.doc = doc
+ self.active_history = active_history
self.join_depth = join_depth
self.local_remote_pairs = _local_remote_pairs
self.extension = extension
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 5c608d1f4..a56b67546 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1523,7 +1523,10 @@ class Query(object):
else:
return list(res)
else:
- return list(self[item:item+1])[0]
+ if item == -1:
+ return list(self)[-1]
+ else:
+ return list(self[item:item+1])[0]
@_generative(_no_statement_condition)
def slice(self, start, stop):
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 17f165b64..578ef2de1 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -109,7 +109,8 @@ class ColumnLoader(LoaderStrategy):
self.is_class_level = True
coltype = self.columns[0].type
# TODO: check all columns ? check for foreign key as well?
- active_history = self.columns[0].primary_key
+ active_history = self.parent_property.active_history or \
+ self.columns[0].primary_key
_register_attribute(self, mapper, useobject=False,
compare_function=coltype.compare_values,
@@ -164,8 +165,7 @@ class CompositeColumnLoader(ColumnLoader):
_register_attribute(self, mapper, useobject=False,
compare_function=compare,
copy_function=copy,
- mutable_scalars=True
- #active_history ?
+ mutable_scalars=True,
)
def create_row_processor(self, selectcontext, path, mapper,
@@ -399,6 +399,7 @@ class LazyLoader(AbstractRelationshipLoader):
uselist = self.parent_property.uselist,
typecallable = self.parent_property.collection_class,
active_history = \
+ self.parent_property.active_history or \
self.parent_property.direction is not \
interfaces.MANYTOONE or \
not self.use_get,