- worked through about 25% of mappers.rst to implement

up to date and clear explanations of things, including
as much context and description as possible
This commit is contained in:
Mike Bayer
2010-08-01 20:55:44 -04:00
parent dada8ce27f
commit 2f844f231c
7 changed files with 267 additions and 118 deletions
+2
View File
@@ -36,6 +36,8 @@ extensions = ['sphinx.ext.autodoc',
# Add any paths that contain templates here, relative to this directory.
templates_path = ['templates']
nitpicky = True
# The suffix of source filenames.
source_suffix = '.rst'
+199 -47
View File
@@ -3,49 +3,146 @@
====================
Mapper Configuration
====================
This section references most major configurational patterns involving the :func:`~sqlalchemy.orm.mapper` and :func:`~sqlalchemy.orm.relationship` functions. It assumes you've worked through :ref:`ormtutorial_toplevel` and know how to construct and use rudimentary mappers and relationships.
This section references most major configurational patterns involving the
:func:`~.orm.mapper` and :func:`.relationship` functions. It assumes you've
worked through :ref:`ormtutorial_toplevel` and know how to construct and use
rudimentary mappers and relationships.
Mapper Configuration
====================
This section describes a variety of configurational patterns that are usable
with mappers. Most of these examples apply equally well
to the usage of distinct :func:`~.orm.mapper` and :class:`.Table` objects
as well as when using the :mod:`sqlalchemy.ext.declarative` extension.
Any example in this section which takes a form such as::
mapper(User, users_table, primary_key=[users_table.c.id])
Would translate into declarative as::
class User(Base):
__table__ = users_table
__mapper_args__ = {
'primary_key':users_table.c.id
}
Or if using ``__tablename__``, :class:`.Column` objects are declared inline
with the class definition. These are usable as is within ``__mapper_args__``::
class User(Base):
__tablename__ = 'users'
id = Column(Integer)
__mapper_args__ = {
'primary_key':id
}
For a full reference of all options available on mappers, please see the API
description of :func:`~.orm.mapper`.
Customizing Column Properties
------------------------------
The default behavior of a ``mapper`` is to assemble all the columns in the mapped :class:`~sqlalchemy.schema.Table` into mapped object attributes. This behavior can be modified in several ways, as well as enhanced by SQL expressions.
The default behavior of :func:`~.orm.mapper` is to assemble all the columns in
the mapped :class:`.Table` into mapped object attributes. This behavior can be
modified in several ways, as well as enhanced by SQL expressions.
To load only a part of the columns referenced by a table as attributes, use the ``include_properties`` and ``exclude_properties`` arguments::
Mapping a Subset of Table Columns
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To reference a subset of columns referenced by a table as mapped attributes,
use the ``include_properties`` or ``exclude_properties`` arguments. For
example::
mapper(User, users_table, include_properties=['user_id', 'user_name'])
Will map the ``User`` class to the ``users_table`` table, only including
the "user_id" and "user_name" columns - the rest are not refererenced.
Similarly::
mapper(Address, addresses_table, exclude_properties=['street', 'city', 'state', 'zip'])
mapper(Address, addresses_table,
exclude_properties=['street', 'city', 'state', 'zip'])
To change the name of the attribute mapped to a particular column, place the :class:`~sqlalchemy.schema.Column` object in the ``properties`` dictionary with the desired key::
will map the ``Address`` class to the ``addresses_table`` table, including
all columns present except "street", "city", "state", and "zip".
When this mapping is used, the columns that are not included will not be
referenced in any SELECT statements emitted by :class:`.Query`, nor will there
be any mapped attribute on the mapped class which represents the column;
setting a value on the mapped class to a name which matches an un-mapped
column will have no effect.
It should be noted however that "default", "on_update", "server_default" and
"server_onupdate" attributes configured on the :class:`.Column` *will* continue to function normally. The columns are ignored only at the mapper
level, but not at the SQL expression level. The ORM uses the SQL expression
system to emit SQL to the database.
Attribute Names for Mapped Columns
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To change the name of the attribute mapped to a particular column, place the
:class:`~sqlalchemy.schema.Column` object in the ``properties`` dictionary
with the desired key::
mapper(User, users_table, properties={
'id': users_table.c.user_id,
'name': users_table.c.user_name,
})
To change the names of all attributes using a prefix, use the ``column_prefix`` option. This is useful for classes which wish to add their own ``property`` accessors::
When using :mod:`~sqlalchemy.ext.declarative`, the above configuration is more
succinct - place the full column name in the :class:`.Column` definition,
using the desired attribute name in the class definition::
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column('user_id', Integer, primary_key=True)
name = Column('user_name', String(50))
To change the names of all attributes using a prefix, use the
``column_prefix`` option. This is useful for some schemes that would like
to declare alternate attributes::
mapper(User, users_table, column_prefix='_')
The above will place attribute names such as ``_user_id``, ``_user_name``, ``_password`` etc. on the mapped ``User`` class.
The above will place attribute names such as ``_user_id``, ``_user_name``,
``_password`` etc. on the mapped ``User`` class.
To place multiple columns which are known to be "synonymous" based on foreign key relationship or join condition into the same mapped attribute, put them together using a list, as below where we map to a :class:`~sqlalchemy.sql.expression.Join`::
Mapping Multiple Columns to a Single Attribute
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To place multiple columns which are known to be "synonymous" based on foreign
key relationship or join condition into the same mapped attribute, put them
together using a list, as below where we map to a :func:`~.expression.join`::
from sqlalchemy.sql import join
# join users and addresses
usersaddresses = sql.join(users_table, addresses_table, \
usersaddresses = join(users_table, addresses_table, \
users_table.c.user_id == addresses_table.c.user_id)
# user_id columns are equated under the 'user_id' attribute
mapper(User, usersaddresses, properties={
'id':[users_table.c.user_id, addresses_table.c.user_id],
})
For further examples on this particular use case, see :ref:`maptojoin`.
Deferred Column Loading
------------------------
This feature allows particular columns of a table to not be loaded by default, instead being loaded later on when first referenced. It is essentially "column-level lazy loading". This feature is useful when one wants to avoid loading a large text or binary field into memory when it's not needed. Individual columns can be lazy loaded by themselves or placed into groups that lazy-load together::
This feature allows particular columns of a table to not be loaded by default,
instead being loaded later on when first referenced. It is essentially
"column-level lazy loading". This feature is useful when one wants to avoid
loading a large text or binary field into memory when it's not needed.
Individual columns can be lazy loaded by themselves or placed into groups that
lazy-load together::
book_excerpts = Table('books', db,
Column('book_id', Integer, primary_key=True),
@@ -91,17 +188,19 @@ Deferred columns can be placed into groups so that they load together::
'photo3': deferred(book_excerpts.c.photo3, group='photos')
})
You can defer or undefer columns at the :class:`~sqlalchemy.orm.query.Query` level using the ``defer`` and ``undefer`` options::
You can defer or undefer columns at the :class:`~sqlalchemy.orm.query.Query` level using the :func:`.defer` and :func:`.undefer` query options::
query = session.query(Book)
query.options(defer('summary')).all()
query.options(undefer('excerpt')).all()
And an entire "deferred group", i.e. which uses the ``group`` keyword argument to :func:`~sqlalchemy.orm.deferred()`, can be undeferred using :func:`~sqlalchemy.orm.undefer_group()`, sending in the group name::
And an entire "deferred group", i.e. which uses the ``group`` keyword argument to :func:`~sqlalchemy.orm.deferred()`, can be undeferred using :func:`.undefer_group()`, sending in the group name::
query = session.query(Book)
query.options(undefer_group('photos')).all()
.. _mapper_sql_expressions:
SQL Expressions as Mapped Attributes
-------------------------------------
@@ -129,15 +228,15 @@ Correlated subqueries may be used as well:
Changing Attribute Behavior
----------------------------
Simple Validators
~~~~~~~~~~~~~~~~~~
A quick way to add a "validation" routine to an attribute is to use the :func:`~sqlalchemy.orm.validates` decorator. This is a shortcut for using the :class:`sqlalchemy.orm.util.Validator` attribute extension with individual column or relationship based attributes. An attribute validator can raise an exception, halting the process of mutating the attribute's value, or can change the given value into something different. Validators, like all attribute extensions, are only called by normal userland code; they are not issued when the ORM is populating the object.
A quick way to add a "validation" routine to an attribute is to use the :func:`~sqlalchemy.orm.validates` decorator. An attribute validator can raise an exception, halting the process of mutating the attribute's value, or can change the given value into something different. Validators, like all attribute extensions, are only called by normal userland code; they are not issued when the ORM is populating the object.
.. sourcecode:: python+sql
from sqlalchemy.orm import validates
addresses_table = Table('addresses', metadata,
Column('id', Integer, primary_key=True),
Column('email', String)
@@ -202,51 +301,77 @@ The ``email`` attribute is now usable in the same way as any other mapped attrib
If the mapped class does not provide a property, the :func:`~sqlalchemy.orm.synonym` construct will create a default getter/setter object automatically.
To use synonyms with :mod:`~sqlalchemy.ext.declarative`, see the section
:ref:`declarative_synonyms`.
.. _custom_comparators:
Custom Comparators
~~~~~~~~~~~~~~~~~~~
The expressions returned by comparison operations, such as ``User.name=='ed'``, can be customized. SQLAlchemy attributes generate these expressions using :class:`~sqlalchemy.orm.interfaces.PropComparator` objects, which provide common Python expression overrides including ``__eq__()``, ``__ne__()``, ``__lt__()``, and so on. Any mapped attribute can be passed a user-defined class via the ``comparator_factory`` keyword argument, which subclasses the appropriate :class:`~sqlalchemy.orm.interfaces.PropComparator` in use, which can provide any or all of these methods:
The expressions returned by comparison operations, such as
``User.name=='ed'``, can be customized, by implementing an object that
explicitly defines each comparison method needed. This is a relatively rare
use case. For most needs, the approach in :ref:`mapper_sql_expressions` will
often suffice, or alternatively a scheme like that of the
:mod:`.derived_attributes` example. Those approaches should be tried first
before resorting to custom comparison objects.
.. sourcecode:: python+sql
Each of :func:`.column_property`, :func:`~.composite`, :func:`.relationship`, and :func:`.comparable_property` accept an argument called ``comparator_factory``. A subclass of :class:`.PropComparator` can be
provided for this argument, which can then reimplement basic Python comparison
methods such as ``__eq__()``, ``__ne__()``, ``__lt__()``, and so on. See
each of those functions for subclassing guidelines, as it's usually best to
subclass the :class:`.PropComparator` subclass used by that type of
property, so that all methods remain implemented. For example, to
allow a column-mapped attribute to do case-insensitive
comparison::
from sqlalchemy.orm.properties import ColumnProperty
from sqlalchemy.sql import func
class MyComparator(ColumnProperty.Comparator):
def __eq__(self, other):
return func.lower(self.__clause_element__()) == func.lower(other)
mapper(EmailAddress, addresses_table, properties={
'email':column_property(addresses_table.c.email, comparator_factory=MyComparator)
'email':column_property(addresses_table.c.email,
comparator_factory=MyComparator)
})
Above, comparisons on the ``email`` column are wrapped in the SQL lower() function to produce case-insensitive matching:
.. sourcecode:: python+sql
Above, comparisons on the ``email`` column are wrapped in the SQL lower() function to produce case-insensitive matching::
>>> str(EmailAddress.email == 'SomeAddress@foo.com')
lower(addresses.email) = lower(:lower_1)
The ``__clause_element__()`` method is provided by the base ``Comparator`` class in use, and represents the SQL element which best matches what this attribute represents. For a column-based attribute, it's the mapped column. For a composite attribute, it's a :class:`~sqlalchemy.sql.expression.ClauseList` consisting of each column represented. For a relationship, it's the table mapped by the local mapper (not the remote mapper). ``__clause_element__()`` should be honored by the custom comparator class in most cases since the resulting element will be applied any translations which are in effect, such as the correctly aliased member when using an ``aliased()`` construct or certain :func:`~sqlalchemy.orm.query.Query.with_polymorphic` scenarios.
In contrast, a similar effect is more easily accomplished, although
with less control of it's behavior, using a column-mapped expression::
from sqlachemy.orm import column_property
from sqlalchemy.sql import func
mapper(EmailAddress, addresses_table, properties={
'email':column_property(func.lower(addresses_table.c.email))
})
There are four kinds of ``Comparator`` classes which may be subclassed, as according to the type of mapper property configured:
In the above case, the "email" attribute will be rendered as ``lower(email)``
in all queries, including in the columns clause of the SELECT statement.
This means the value of "email" will be loaded as lower case, not just in
comparisons. It's up to the user to decide if the finer-grained control
but more upfront work of a custom :class:`.PropComparator` is necessary.
* :func:`~sqlalchemy.orm.column_property` attribute - ``sqlalchemy.orm.properties.ColumnProperty.Comparator``
* :func:`~sqlalchemy.orm.composite` attribute - ``sqlalchemy.orm.properties.CompositeProperty.Comparator``
* :func:`~sqlalchemy.orm.relationship` attribute - ``sqlalchemy.orm.properties.RelationshipProperty.Comparator``
* :func:`~sqlalchemy.orm.comparable_property` attribute - ``sqlalchemy.orm.interfaces.PropComparator``
When using :func:`~sqlalchemy.orm.comparable_property`, which is a mapper property that isn't tied to any column or mapped table, the ``__clause_element__()`` method of :class:`~sqlalchemy.orm.interfaces.PropComparator` should also be implemented.
The ``comparator_factory`` argument is accepted by all ``MapperProperty``-producing functions: :func:`~sqlalchemy.orm.column_property`, :func:`~sqlalchemy.orm.composite`, :func:`~sqlalchemy.orm.comparable_property`, :func:`~sqlalchemy.orm.synonym`, :func:`~sqlalchemy.orm.relationship`, :func:`~sqlalchemy.orm.backref`, :func:`~sqlalchemy.orm.deferred`, and :func:`~sqlalchemy.orm.dynamic_loader`.
.. _mapper_composite:
Composite Column Types
-----------------------
Sets of columns can be associated with a single datatype. The ORM treats the group of columns like a single column which accepts and returns objects using the custom datatype you provide. In this example, we'll create a table ``vertices`` which stores a pair of x/y coordinates, and a custom datatype ``Point`` which is a composite type of an x and y column:
Sets of columns can be associated with a single user-defined datatype. The ORM provides a single attribute which represents the group of columns
using the class you provide.
.. sourcecode:: python+sql
A simple example represents pairs of columns as a "Point" object.
Starting with a table that represents two points as x1/y1 and x2/y2::
from sqlalchemy import Table, Column
vertices = Table('vertices', metadata,
Column('id', Integer, primary_key=True),
Column('x1', Integer),
@@ -255,25 +380,39 @@ Sets of columns can be associated with a single datatype. The ORM treats the gr
Column('y2', Integer),
)
The requirements for the custom datatype class are that it have a constructor which accepts positional arguments corresponding to its column format, and also provides a method ``__composite_values__()`` which returns the state of the object as a list or tuple, in order of its column-based attributes. It also should supply adequate ``__eq__()`` and ``__ne__()`` methods which test the equality of two instances, and may optionally provide a ``__set_composite_values__`` method which is used to set internal state in some cases (typically when default values have been generated during a flush)::
We create a new class, ``Point``, that will represent each x/y as a
pair::
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __composite_values__(self):
return [self.x, self.y]
return self.x, self.y
def __set_composite_values__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return other.x == self.x and other.y == self.y
return other is not None and \
other.x == self.x and \
other.y == self.y
def __ne__(self, other):
return not self.__eq__(other)
If ``__set_composite_values__()`` is not provided, the names of the mapped columns are taken as the names of attributes on the object, and ``setattr()`` is used to set data.
The requirements for the custom datatype class are that it have a
constructor which accepts positional arguments corresponding to its column
format, and also provides a method ``__composite_values__()`` which
returns the state of the object as a list or tuple, in order of its
column-based attributes. It also should supply adequate ``__eq__()`` and
``__ne__()`` methods which test the equality of two instances.
Setting up the mapping uses the :func:`~sqlalchemy.orm.composite()` function::
The ``__set_composite_values__()`` method is optional. If it's not
provided, the names of the mapped columns are taken as the names of
attributes on the object, and ``setattr()`` is used to set data.
The :func:`.composite` function is then used in the mapping::
from sqlalchemy.orm import mapper, composite
class Vertex(object):
pass
@@ -283,30 +422,37 @@ Setting up the mapping uses the :func:`~sqlalchemy.orm.composite()` function::
'end': composite(Point, vertices.c.x2, vertices.c.y2)
})
We can now use the ``Vertex`` instances as well as querying as though the ``start`` and ``end`` attributes are regular scalar attributes::
We can now use the ``Vertex`` instances as well as querying as though the
``start`` and ``end`` attributes are regular scalar attributes::
session = Session()
v = Vertex(Point(3, 4), Point(5, 6))
session.save(v)
session.add(v)
v2 = session.query(Vertex).filter(Vertex.start == Point(3, 4))
The "equals" comparison operation by default produces an AND of all corresponding columns equated to one another. This can be changed using the ``comparator_factory``, described in :ref:`custom_comparators`::
The "equals" comparison operation by default produces an AND of all
corresponding columns equated to one another. This can be changed using
the ``comparator_factory``, described in :ref:`custom_comparators`.
Below we illustrate the "greater than" operator, implementing
the same expression that the base "greater than" does::
from sqlalchemy.orm.properties import CompositeProperty
from sqlalchemy import sql
class PointComparator(CompositeProperty.Comparator):
def __gt__(self, other):
"""define the 'greater than' operation"""
"""redefine the 'greater than' operation"""
return sql.and_(*[a>b for a, b in
zip(self.__clause_element__().clauses,
other.__composite_values__())])
maper(Vertex, vertices, properties={
'start': composite(Point, vertices.c.x1, vertices.c.y1, comparator_factory=PointComparator),
'end': composite(Point, vertices.c.x2, vertices.c.y2, comparator_factory=PointComparator)
'start': composite(Point, vertices.c.x1, vertices.c.y1,
comparator_factory=PointComparator),
'end': composite(Point, vertices.c.x2, vertices.c.y2,
comparator_factory=PointComparator)
})
Controlling Ordering
@@ -744,6 +890,8 @@ The big limitation with concrete table inheritance is that :func:`~sqlalchemy.or
})
.. _maptojoin:
Mapping a Class against Multiple Tables
----------------------------------------
@@ -751,7 +899,8 @@ Mappers can be constructed against arbitrary relational units (called ``Selectab
.. sourcecode:: python+sql
# a class
from sqlalchemy.sql import join
class AddressUser(object):
pass
@@ -768,6 +917,8 @@ A second example:
.. sourcecode:: python+sql
from sqlalchemy.sql import join
# many-to-many join on an association table
j = join(users_table, userkeywords,
users_table.c.user_id==userkeywords.c.user_id).join(keywords,
@@ -789,11 +940,12 @@ In both examples above, "composite" columns were added as properties to the mapp
Mapping a Class against Arbitrary Selects
------------------------------------------
Similar to mapping against a join, a plain select() object can be used with a mapper as well. Below, an example select which contains two aggregate functions and a group_by is mapped to a class:
.. sourcecode:: python+sql
from sqlalchemy.sql import select
s = select([customers,
func.count(orders).label('order_count'),
func.max(orders.price).label('highest_order')],
+6 -2
View File
@@ -8,7 +8,7 @@ Querying
The Query Object
----------------
:class:`~sqlalchemy.orm.query.Query` is produced in terms of a given :class:`~sqlalchemy.orm.session.Session`, using the :func:`~sqlalchemy.orm.query.Query.query` function::
:class:`~.Query` is produced in terms of a given :class:`~.Session`, using the :func:`~.Query.query` function::
q = session.query(SomeMappedClass)
@@ -21,7 +21,9 @@ Following is the full interface for the :class:`Query` object.
ORM-Specific Query Constructs
-----------------------------
.. autoclass:: aliased
.. class:: aliased
The public name of the :class:`.AliasedClass` class.
.. autoclass:: sqlalchemy.orm.util.AliasedClass
@@ -58,3 +60,5 @@ Options which are passed to ``query.options()``, to affect the behavior of loadi
.. autofunction:: undefer
.. autofunction:: undefer_group
+2
View File
@@ -180,6 +180,8 @@ a many-to-many relationship, since the ORM may issue duplicate INSERT and
DELETE statements.
.. _declarative_synonyms:
Defining Synonyms
=================
+36 -64
View File
@@ -519,27 +519,27 @@ def column_property(*args, **kwargs):
Columns that aren't present in the mapper's selectable won't be persisted
by the mapper and are effectively "read-only" attributes.
\*cols
:param \*cols:
list of Column objects to be mapped.
comparator_factory
a class which extends ``sqlalchemy.orm.properties.ColumnProperty.Comparator``
:param comparator_factory:
a class which extends :class:`sqlalchemy.orm.properties.ColumnProperty.Comparator`
which provides custom SQL clause generation for comparison operations.
group
a group name for this property when marked as deferred.
:param group:
a group name for this property when marked as deferred.
deferred
:param 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
:func:`~sqlalchemy.orm.deferred`.
doc
:param doc:
optional string that will be applied as the doc on the
class-bound descriptor.
extension
:param extension:
an :class:`~sqlalchemy.orm.interfaces.AttributeExtension` instance,
or list of extensions, which will be prepended to the list of
attribute listeners for the resulting descriptor placed on the class.
@@ -553,70 +553,33 @@ def column_property(*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.
The class must implement a constructor with positional arguments matching
the order of columns supplied here, as well as a __composite_values__()
method which returns values in the same order.
A simple example is representing separate two columns in a table as a
single, first-class "Point" object::
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __composite_values__(self):
return self.x, self.y
def __eq__(self, other):
return other is not None and self.x == other.x and self.y == other.y
# and then in the mapping:
... composite(Point, mytable.c.x, mytable.c.y) ...
The composite object may have its attributes populated based on the names
of the mapped columns. To override the way internal state is set,
additionally implement ``__set_composite_values__``::
class Point(object):
def __init__(self, x, y):
self.some_x = x
self.some_y = y
def __composite_values__(self):
return self.some_x, self.some_y
def __set_composite_values__(self, x, y):
self.some_x = x
self.some_y = y
def __eq__(self, other):
return other is not None and self.some_x == other.x and self.some_y == other.y
Arguments are:
class\_
See the mapping documention section :ref:`mapper_composite` for a full
usage example.
:param class\_:
The "composite type" class.
\*cols
:param \*cols:
List of Column objects to be mapped.
group
:param group:
A group name for this property when marked as deferred.
deferred
:param 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 :func:`~sqlalchemy.orm.deferred`.
comparator_factory
a class which extends :class:`~sqlalchemy.orm.properties.CompositeProperty.Comparator`
:param comparator_factory:
a class which extends :class:`sqlalchemy.orm.properties.CompositeProperty.Comparator`
which provides custom SQL clause generation for comparison operations.
doc
:param doc:
optional string that will be applied as the doc on the
class-bound descriptor.
extension
:param extension:
an :class:`~sqlalchemy.orm.interfaces.AttributeExtension` instance,
or list of extensions, which will be prepended to the list of
attribute listeners for the resulting descriptor placed on the class.
@@ -869,25 +832,34 @@ def comparable_property(comparator_factory, descriptor=None):
(__eq__) to the supplied comparator but proxies everything else through to
the original descriptor::
from sqlalchemy.orm import mapper, comparable_property
from sqlalchemy.orm.interfaces import PropComparator
from sqlalchemy.sql import func
class MyClass(object):
@property
def myprop(self):
return 'foo'
class MyComparator(sqlalchemy.orm.interfaces.PropComparator):
class MyComparator(PropComparator):
def __eq__(self, other):
....
return func.lower(other) == foo
mapper(MyClass, mytable, properties=dict(
'myprop': comparable_property(MyComparator)))
mapper(MyClass, mytable, properties={
'myprop': comparable_property(MyComparator)})
Used with the ``properties`` dictionary sent to :func:`~sqlalchemy.orm.mapper`.
comparator_factory
Note that :func:`comparable_property` is usually not needed for basic
needs. The recipe at :mod:`.derived_attributes` offers a simpler pure-Python
method of achieving a similar result using class-bound attributes with
SQLAlchemy expression constructs.
:param comparator_factory:
A PropComparator subclass or factory that defines operator behavior
for this property.
descriptor
:param descriptor:
Optional when used in a ``properties={}`` declaration. The Python
descriptor or property to layer comparison behavior on top of.
+21 -4
View File
@@ -54,7 +54,20 @@ def _generative(*assertions):
return generate
class Query(object):
"""ORM-level SQL construction object."""
"""ORM-level SQL construction object.
:class:`.Query` is the source of all SELECT statements generated by the
ORM, both those formulated by end-user query operations as well as by
high level internal operations such as related collection loading. It
features a generative interface whereby successive calls return a new
:class:`.Query` object, a copy of the former with additional
criteria and options associated with it.
:class:`.Query` objects are normally initially generated using the
:meth:`~.Session.query` method of :class:`.Session`. For a full walkthrough
of :class:`.Query` usage, see the :ref:`ormtutorial_toplevel`.
"""
_enable_eagerloads = True
_enable_assertions = True
@@ -732,10 +745,14 @@ class Query(object):
# given arg is a FROM clause
self._setup_aliasizers(self._entities[l:])
@util.pending_deprecation("add_column() superceded by add_columns()")
@util.pending_deprecation("0.7", "add_column() is superceded by 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 superceded by
:meth:`.add_columns`.
"""
return self.add_columns(column)
+1 -1
View File
@@ -1668,7 +1668,7 @@ def pending_deprecation(version, message=None,
"""
if add_deprecation_to_docstring:
header = message is not None and message or 'Deprecated.'
header = ".. deprecated:: %s (pending) %s" % (version, (message or ''))
else:
header = None