summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-07-18 19:08:31 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-07-18 19:08:31 -0400
commite8ff3047c6596d39bb38956eb5aba5651c104e63 (patch)
treecbcc704e9388fba6f16bd914c2beede244be9dc8
parent9c0de7fcf7fc56701af446742fe876335aef15b1 (diff)
downloadsqlalchemy-e8ff3047c6596d39bb38956eb5aba5651c104e63.tar.gz
a lot of docs
-rw-r--r--doc/build/core/expression_api.rst6
-rw-r--r--doc/build/core/inspection.rst5
-rw-r--r--doc/build/orm/index.rst1
-rw-r--r--doc/build/orm/interfaces.rst1
-rw-r--r--doc/build/orm/internals.rst12
-rw-r--r--doc/build/orm/query.rst4
-rw-r--r--lib/sqlalchemy/orm/attributes.py48
-rw-r--r--lib/sqlalchemy/orm/state.py17
-rw-r--r--lib/sqlalchemy/orm/util.py135
-rw-r--r--lib/sqlalchemy/sql/expression.py80
10 files changed, 213 insertions, 96 deletions
diff --git a/doc/build/core/expression_api.rst b/doc/build/core/expression_api.rst
index a49fa38fb..de9181252 100644
--- a/doc/build/core/expression_api.rst
+++ b/doc/build/core/expression_api.rst
@@ -106,6 +106,10 @@ Classes
:members:
:show-inheritance:
+.. autoclass:: BinaryExpression
+ :members:
+ :show-inheritance:
+
.. autoclass:: BindParameter
:members:
:show-inheritance:
@@ -195,7 +199,7 @@ Classes
:members:
:show-inheritance:
-.. autoclass:: sqlalchemy.sql.expression.Operators
+.. autoclass:: sqlalchemy.sql.operators.Operators
:members:
:undoc-members:
diff --git a/doc/build/core/inspection.rst b/doc/build/core/inspection.rst
index 2fc371d84..777ee944e 100644
--- a/doc/build/core/inspection.rst
+++ b/doc/build/core/inspection.rst
@@ -18,7 +18,10 @@ Following is a listing of all inspection targets.
meaning any of these objects passed to :func:`.inspect` return themselves.
* ``object`` - an object given will be checked by the ORM for a mapping -
if so, an :class:`.InstanceState` is returned representing the mapped
- state of the object.
+ state of the object. The :class:`.InstanceState` also provides access
+ to per attribute state via the :class:`.AttributeState` interface as well
+ as the per-flush "history" of any attribute via the :class:`.History`
+ object.
* ``type`` (i.e. a class) - a class given will be checked by the ORM for a
mapping - if so, a :class:`.Mapper` for that class is returned.
* mapped attribute - passing a mapped attribute to :func:`.inspect`, such
diff --git a/doc/build/orm/index.rst b/doc/build/orm/index.rst
index 0c461fb6d..6c12ebd38 100644
--- a/doc/build/orm/index.rst
+++ b/doc/build/orm/index.rst
@@ -22,6 +22,5 @@ tutorial.
events
extensions/index
examples
- interfaces
exceptions
internals
diff --git a/doc/build/orm/interfaces.rst b/doc/build/orm/interfaces.rst
deleted file mode 100644
index bedbeca40..000000000
--- a/doc/build/orm/interfaces.rst
+++ /dev/null
@@ -1 +0,0 @@
-This page has moved to :ref:`dep_interfaces_orm_toplevel`.
diff --git a/doc/build/orm/internals.rst b/doc/build/orm/internals.rst
index 301156f8b..4f640b265 100644
--- a/doc/build/orm/internals.rst
+++ b/doc/build/orm/internals.rst
@@ -3,10 +3,15 @@
ORM Internals
=============
-Some key internal constructs are listed here.
+Key ORM constructs, not otherwise covered in other
+sections, are listed here.
.. currentmodule: sqlalchemy.orm
+.. autoclass:: sqlalchemy.orm.state.AttributeState
+ :members:
+ :show-inheritance:
+
.. autoclass:: sqlalchemy.orm.instrumentation.ClassManager
:members:
:show-inheritance:
@@ -23,10 +28,6 @@ Some key internal constructs are listed here.
:members:
:show-inheritance:
-.. autoclass:: sqlalchemy.orm.state.InspectAttr
- :members:
- :show-inheritance:
-
.. autoclass:: sqlalchemy.orm.interfaces.MapperProperty
:members:
:show-inheritance:
@@ -39,7 +40,6 @@ Some key internal constructs are listed here.
:members:
:show-inheritance:
-
.. autoclass:: sqlalchemy.orm.descriptor_props.SynonymProperty
:members:
:show-inheritance:
diff --git a/doc/build/orm/query.rst b/doc/build/orm/query.rst
index d143908eb..dcd7ec40e 100644
--- a/doc/build/orm/query.rst
+++ b/doc/build/orm/query.rst
@@ -26,9 +26,7 @@ Following is the full interface for the :class:`.Query` object.
ORM-Specific Query Constructs
-----------------------------
-.. class:: aliased
-
-The public name of the :class:`.AliasedClass` class.
+.. autofunction:: sqlalchemy.orm.aliased
.. autoclass:: sqlalchemy.orm.util.AliasedClass
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index d335d8996..47349e64a 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -786,9 +786,12 @@ class CollectionAttributeImpl(AttributeImpl):
original_set = dict(original_states)
return \
- [(s, o) for s, o in current_states if s not in original_set] + \
- [(s, o) for s, o in current_states if s in original_set] + \
- [(s, o) for s, o in original_states if s not in current_set]
+ [(s, o) for s, o in current_states
+ if s not in original_set] + \
+ [(s, o) for s, o in current_states
+ if s in original_set] + \
+ [(s, o) for s, o in original_states
+ if s not in current_set]
return [(instance_state(o), o) for o in current]
@@ -1036,32 +1039,35 @@ _NO_STATE_SYMBOLS = frozenset([
id(PASSIVE_NO_RESULT),
id(NO_VALUE),
id(NEVER_SET)])
-class History(tuple):
+
+History = util.namedtuple("History", [
+ "added", "unchanged", "deleted"
+ ])
+
+class History(History):
"""A 3-tuple of added, unchanged and deleted values,
representing the changes which have occurred on an instrumented
attribute.
- Each tuple member is an iterable sequence.
+ The easiest way to get a :class:`.History` object for a particular
+ attribute on an object is to use the :func:`.inspect` function::
- """
+ from sqlalchemy import inspect
- __slots__ = ()
+ hist = inspect(myobject).attr.myattribute.history
- added = property(itemgetter(0))
- """Return the collection of items added to the attribute (the first tuple
- element)."""
+ Each tuple member is an iterable sequence:
- unchanged = property(itemgetter(1))
- """Return the collection of items that have not changed on the attribute
- (the second tuple element)."""
+ * ``added`` - the collection of items added to the attribute (the first
+ tuple element).
+ * ``unchanged`` - the collection of items that have not changed on the
+ attribute (the second tuple element).
- deleted = property(itemgetter(2))
- """Return the collection of items that have been removed from the
- attribute (the third tuple element)."""
+ * ``deleted`` - the collection of items that have been removed from the
+ attribute (the third tuple element).
- def __new__(cls, added, unchanged, deleted):
- return tuple.__new__(cls, (added, unchanged, deleted))
+ """
def __nonzero__(self):
return self != HISTORY_BLANK
@@ -1178,10 +1184,12 @@ class History(tuple):
return cls((), list(current), ())
else:
- current_states = [((c is not None) and instance_state(c) or None, c)
+ current_states = [((c is not None) and instance_state(c)
+ or None, c)
for c in current
]
- original_states = [((c is not None) and instance_state(c) or None, c)
+ original_states = [((c is not None) and instance_state(c)
+ or None, c)
for c in original
]
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 9307c94da..1c7fc2c41 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -54,12 +54,12 @@ class InstanceState(interfaces._InspectionAttr):
the mapped object, including its current value
and history.
- The returned object is an instance of :class:`.InspectAttr`.
+ The returned object is an instance of :class:`.AttributeState`.
"""
return util.ImmutableProperties(
dict(
- (key, InspectAttr(self, key))
+ (key, AttributeState(self, key))
for key in self.manager
)
)
@@ -508,13 +508,18 @@ class InstanceState(interfaces._InspectionAttr):
state.modified = state.expired = False
state._strong_obj = None
-class InspectAttr(object):
+class AttributeState(object):
"""Provide an inspection interface corresponding
to a particular attribute on a particular mapped object.
- The :class:`.InspectAttr` object is created by
- accessing the :attr:`.InstanceState.attr`
- collection.
+ The :class:`.AttributeState` object is accessed
+ via the :attr:`.InstanceState.attr` collection
+ of a particular :class:`.InstanceState`::
+
+ from sqlalchemy import inspect
+
+ insp = inspect(some_mapped_object)
+ attr_state = insp.attr.some_attribute
"""
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index 97bf4e7a9..8f340d366 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -386,7 +386,10 @@ class AliasedClass(object):
__getattr__ scheme and maintains a reference to a
real :class:`~sqlalchemy.sql.expression.Alias` object.
- Usage is via the :class:`~sqlalchemy.orm.aliased()` synonym::
+ Usage is via the :func:`.orm.aliased` function, or alternatively
+ via the :func:`.orm.with_polymorphic` function.
+
+ Usage example::
# find all pairs of users with the same name
user_alias = aliased(User)
@@ -394,51 +397,25 @@ class AliasedClass(object):
join((user_alias, User.id > user_alias.id)).\\
filter(User.name==user_alias.name)
- The resulting object is an instance of :class:`.AliasedClass`, however
- it implements a ``__getattribute__()`` scheme which will proxy attribute
- access to that of the ORM class being aliased. All classmethods
- on the mapped entity should also be available here, including
- hybrids created with the :ref:`hybrids_toplevel` extension,
- which will receive the :class:`.AliasedClass` as the "class" argument
- when classmethods are called.
-
- :param cls: ORM mapped entity which will be "wrapped" around an alias.
- :param alias: a selectable, such as an :func:`.alias` or :func:`.select`
- construct, which will be rendered in place of the mapped table of the
- ORM entity. If left as ``None``, an ordinary :class:`.Alias` of the
- ORM entity's mapped table will be generated.
- :param name: A name which will be applied both to the :class:`.Alias`
- if one is generated, as well as the name present in the "named tuple"
- returned by the :class:`.Query` object when results are returned.
- :param adapt_on_names: if True, more liberal "matching" will be used when
- mapping the mapped columns of the ORM entity to those of the
- given selectable - a name-based match will be performed if the
- given selectable doesn't otherwise have a column that corresponds
- to one on the entity. The use case for this is when associating
- an entity with some derived selectable such as one that uses
- aggregate functions::
-
- class UnitPrice(Base):
- __tablename__ = 'unit_price'
- ...
- unit_id = Column(Integer)
- price = Column(Numeric)
+ The resulting object is an instance of :class:`.AliasedClass`.
+ This object implements an attribute scheme which produces the
+ same attribute and method interface as the original mapped
+ class, allowing :class:`.AliasedClass` to be compatible
+ with any attribute technique which works on the original class,
+ including hybrid attributes (see :ref:`hybrids_toplevel`).
- aggregated_unit_price = Session.query(
- func.sum(UnitPrice.price).label('price')
- ).group_by(UnitPrice.unit_id).subquery()
+ The :class:`.AliasedClass` can be inspected for its underlying
+ :class:`.Mapper`, aliased selectable, and other information
+ using :func:`.inspect`::
- aggregated_unit_price = aliased(UnitPrice,
- alias=aggregated_unit_price, adapt_on_names=True)
+ from sqlalchemy import inspect
+ my_alias = aliased(MyClass)
+ insp = inspect(my_alias)
- Above, functions on ``aggregated_unit_price`` which refer to
- ``.price`` will return the
- ``fund.sum(UnitPrice.price).label('price')`` column, as it is
- matched on the name "price". Ordinarily, the "price" function
- wouldn't have any "column correspondence" to the actual
- ``UnitPrice.price`` column as it is not a proxy of the original.
+ The resulting inspection object is an instance of :class:`.AliasedInsp`.
- .. versionadded:: 0.7.3
+ See :func:`.aliased` and :func:`.with_polymorphic` for construction
+ argument descriptions.
"""
def __init__(self, cls, alias=None,
@@ -601,6 +578,74 @@ class AliasedInsp(_InspectionAttr, AliasedInsp):
inspection._inspects(AliasedClass)(lambda target: target._aliased_insp)
def aliased(element, alias=None, name=None, adapt_on_names=False):
+ """Produce an alias of the given element, usually an :class:`.AliasedClass`
+ instance.
+
+ E.g.::
+
+ my_alias = aliased(MyClass)
+
+ session.query(MyClass, my_alias).filter(MyClass.id > my_alias.id)
+
+ The :func:`.aliased` function is used to create an ad-hoc mapping
+ of a mapped class to a new selectable. By default, a selectable
+ is generated from the normally mapped selectable (typically a
+ :class:`.Table`) using the :meth:`.FromClause.alias` method.
+ However, :func:`.aliased` can also be used to link the class to
+ a new :func:`.select` statement. Also, the :func:`.with_polymorphic`
+ function is a variant of :func:`.aliased` that is intended to specify
+ a so-called "polymorphic selectable", that corresponds to the union
+ of several joined-inheritance subclasses at once.
+
+ For convenience, the :func:`.aliased` function also accepts plain
+ :class:`.FromClause` constructs, such as a :class:`.Table` or
+ :func:`.select` construct. In those cases, the :meth:`.FromClause.alias`
+ method is called on the object and the new :class:`.Alias` object
+ returned. The returned :class:`.Alias` is not ORM-mapped in this case.
+
+ :param element: element to be aliased. Is normally a mapped class,
+ but for convenience can also be a :class:`.FromClause` element.
+ :param alias: Optional selectable unit to map the element to. This should
+ normally be a :class:`.Alias` object corresponding to the :class:`.Table`
+ to which the class is mapped, or to a :func:`.select` construct that
+ is compatible with the mapping. By default, a simple anonymous
+ alias of the mapped table is generated.
+ :param name: optional string name to use for the alias, if not specified
+ by the ``alias`` parameter. The name, among other things, forms the
+ attribute name that will be accessible via tuples returned by a
+ :class:`.Query` object.
+ :param adapt_on_names: if True, more liberal "matching" will be used when
+ mapping the mapped columns of the ORM entity to those of the
+ given selectable - a name-based match will be performed if the
+ given selectable doesn't otherwise have a column that corresponds
+ to one on the entity. The use case for this is when associating
+ an entity with some derived selectable such as one that uses
+ aggregate functions::
+
+ class UnitPrice(Base):
+ __tablename__ = 'unit_price'
+ ...
+ unit_id = Column(Integer)
+ price = Column(Numeric)
+
+ aggregated_unit_price = Session.query(
+ func.sum(UnitPrice.price).label('price')
+ ).group_by(UnitPrice.unit_id).subquery()
+
+ aggregated_unit_price = aliased(UnitPrice,
+ alias=aggregated_unit_price, adapt_on_names=True)
+
+ Above, functions on ``aggregated_unit_price`` which refer to
+ ``.price`` will return the
+ ``fund.sum(UnitPrice.price).label('price')`` column, as it is
+ matched on the name "price". Ordinarily, the "price" function
+ wouldn't have any "column correspondence" to the actual
+ ``UnitPrice.price`` column as it is not a proxy of the original.
+
+ .. versionadded:: 0.7.3
+
+
+ """
if isinstance(element, expression.FromClause):
if adapt_on_names:
raise sa_exc.ArgumentError(
@@ -904,7 +949,7 @@ def object_mapper(instance):
inspect(instance).mapper
- Using the inspection system will raise plain
+ Using the inspection system will raise
:class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
not part of a mapping.
@@ -947,8 +992,8 @@ def class_mapper(class_, configure=True):
inspect(some_mapped_class)
- Using the inspection system will raise plain
- :class:`.InvalidRequestError` if the class is not mapped.
+ Using the inspection system will raise
+ :class:`sqlalchemy.exc.NoInspectionAvailable` if the class is not mapped.
"""
mapper = _inspect_mapped_class(class_, configure=configure)
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index a97ef5ff2..ae25e8c7f 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -1872,8 +1872,11 @@ class Immutable(object):
class CompareMixin(ColumnOperators):
- """Defines comparison and math operations for :class:`.ClauseElement`
- instances.
+ """Defines comparison and math operations.
+
+ The :class:`.CompareMixin` is part of the interface provided
+ by the :class:`.ColumnElement` class, which provides the base class
+ for all SQL expression units.
See :class:`.ColumnOperators` and :class:`.Operators` for descriptions
of all operations.
@@ -2132,21 +2135,40 @@ class ColumnElement(ClauseElement, CompareMixin):
"""Represent an element that is usable within the "column clause" portion
of a ``SELECT`` statement.
- This includes columns associated with tables, aliases, and
+ While the most familiar kind of :class:`.ColumnElement` is the
+ :class:`.Column` object, :class:`.ColumnElement` serves as the basis
+ for any unit that may be present in a SQL expression, including
+ the columns associated with tables, aliases, and
subqueries, expressions, function calls, SQL keywords such as
``NULL``, literals, etc. :class:`.ColumnElement` is the ultimate base
class for all such elements.
+ A :class:`.ColumnElement`, by subclassing the :class:`.CompareMixin` mixin
+ class, provides the ability to generate new :class:`.ClauseElement`
+ objects using Python expressions. This means that Python operators
+ such as ``==``, ``!=`` and ``<`` are overloaded to mimic SQL operations,
+ and allow the construction of :class:`.ColumnElement` constructs which
+ are composed from other, more fundamental :class:`.ColumnElement`
+ objects. For example, two :class:`.ColumnClause` objects can be added
+ together with the addition operator ``+`` to produce
+ a :class:`.BinaryExpression`.
+ Both :class:`.ColumnClause` and :class:`.BinaryExpression` are subclasses
+ of :class:`.ColumnElement`::
+
+ >>> from sqlalchemy.sql import column
+ >>> column('a') + column('b')
+ <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0>
+ >>> print column('a') + column('b')
+ a + b
+
:class:`.ColumnElement` supports the ability to be a *proxy* element,
which indicates that the :class:`.ColumnElement` may be associated with
a :class:`.Selectable` which was derived from another :class:`.Selectable`.
An example of a "derived" :class:`.Selectable` is an :class:`.Alias` of a
- :class:`~sqlalchemy.schema.Table`.
+ :class:`~sqlalchemy.schema.Table`. For the ambitious, an in-depth
+ discussion of this concept can be found at
+ `Expression Transformations <http://techspot.zzzeek.org/2008/01/23/expression-transformations/>`_.
- A :class:`.ColumnElement`, by subclassing the :class:`CompareMixin` mixin
- class, provides the ability to generate new :class:`.ClauseElement`
- objects using Python expressions. See the :class:`CompareMixin`
- docstring for more details.
"""
@@ -2420,6 +2442,19 @@ class FromClause(Selectable):
"""Represent an element that can be used within the ``FROM``
clause of a ``SELECT`` statement.
+ The most common forms of :class:`.FromClause` are the
+ :class:`.Table` and the :func:`.select` constructs. Key
+ features common to all :class:`.FromClause` objects include:
+
+ * a :attr:`.c` collection, which provides per-name access to a collection
+ of :class:`.ColumnElement` objects.
+ * a :attr:`.primary_key` attribute, which is a collection of all those
+ :class:`.ColumnElement` objects that indicate the ``primary_key`` flag.
+ * Methods to generate various derivations of a "from" clause, including
+ :meth:`.FromClause.alias`, :meth:`.FromClause.join`,
+ :meth:`.FromClause.select`.
+
+
"""
__visit_name__ = 'fromclause'
named_with_column = False
@@ -2603,8 +2638,16 @@ class FromClause(Selectable):
@_memoized_property
def columns(self):
- """Return the collection of Column objects contained by this
- FromClause."""
+ """A named-based collection of :class:`.ColumnElement` objects
+ maintained by this :class:`.FromClause`.
+
+ The :attr:`.columns`, or :attr:`.c` collection, is the gateway
+ to the construction of SQL expressions using table-bound or
+ other selectable-bound columns::
+
+ select([mytable]).where(mytable.c.somecolumn == 5)
+
+ """
if '_columns' not in self.__dict__:
self._init_collections()
@@ -2629,7 +2672,8 @@ class FromClause(Selectable):
self._populate_column_collection()
return self.foreign_keys
- c = property(attrgetter('columns'))
+ c = property(attrgetter('columns'),
+ doc="An alias for the :attr:`.columns` attribute.")
_select_iterable = property(attrgetter('columns'))
def _init_collections(self):
@@ -3447,7 +3491,19 @@ class UnaryExpression(ColumnElement):
class BinaryExpression(ColumnElement):
- """Represent an expression that is ``LEFT <operator> RIGHT``."""
+ """Represent an expression that is ``LEFT <operator> RIGHT``.
+
+ A :class:`.BinaryExpression` is generated automatically
+ whenever two objects that subclass the :class:`.CompareMixin`
+ mixin are used in a Python binary expresion::
+
+ >>> from sqlalchemy.sql import column
+ >>> column('a') + column('b')
+ <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0>
+ >>> print column('a') + column('b')
+ a + b
+
+ """
__visit_name__ = 'binary'