summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-08-21 18:10:35 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-08-21 18:10:35 +0000
commit3c80e59ebce9ae404b092011dce70598b563ff23 (patch)
tree0e525cb3c554e9103a5f254fc16e94c8beb72c67 /lib
parentd08821ee5ec566132cb813d2e65e20052c1f712a (diff)
downloadsqlalchemy-3c80e59ebce9ae404b092011dce70598b563ff23.tar.gz
- column_property() and synonym() both accept comparator_factory argument, allowing
custom comparison functionality - made the mapper's checks for user-based descriptors when defining synonym or comparable property stronger, such that a synonym can be used with declarative without having a user-based descriptor
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/__init__.py4
-rw-r--r--lib/sqlalchemy/orm/mapper.py18
-rw-r--r--lib/sqlalchemy/orm/properties.py13
3 files changed, 21 insertions, 14 deletions
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index e405d76a2..da9134b11 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -642,7 +642,7 @@ def mapper(class_, local_table=None, *args, **params):
"""
return Mapper(class_, local_table, *args, **params)
-def synonym(name, map_column=False, descriptor=None, proxy=False):
+def synonym(name, map_column=False, descriptor=None, comparator_factory=None, proxy=False):
"""Set up `name` as a synonym to another mapped property.
Used with the ``properties`` dictionary sent to [sqlalchemy.orm#mapper()].
@@ -684,7 +684,7 @@ def synonym(name, map_column=False, descriptor=None, proxy=False):
is not already available.
"""
- return SynonymProperty(name, map_column=map_column, descriptor=descriptor)
+ return SynonymProperty(name, map_column=map_column, descriptor=descriptor, comparator_factory=comparator_factory)
def comparable_property(comparator_factory, descriptor=None):
"""Provide query semantics for an unmanaged attribute.
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index d1713e6f9..921d08b83 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -640,6 +640,9 @@ class Mapper(object):
return getattr(getattr(cls, clskey), key)
+ def _is_userland_descriptor(self, obj):
+ return not isinstance(obj, (MapperProperty, attributes.InstrumentedAttribute)) and hasattr(obj, '__get__')
+
def _should_exclude(self, name, local):
"""determine whether a particular property should be implicitly present on the class.
@@ -648,18 +651,15 @@ class Mapper(object):
"""
- def is_userland_descriptor(obj):
- return not isinstance(obj, attributes.InstrumentedAttribute) and hasattr(obj, '__get__')
-
# check for descriptors, either local or from
# an inherited class
if local:
if self.class_.__dict__.get(name, None)\
- and is_userland_descriptor(self.class_.__dict__[name]):
+ and self._is_userland_descriptor(self.class_.__dict__[name]):
return True
else:
if getattr(self.class_, name, None)\
- and is_userland_descriptor(getattr(self.class_, name)):
+ and self._is_userland_descriptor(getattr(self.class_, name)):
return True
if (self.include_properties is not None and
@@ -786,9 +786,11 @@ class Mapper(object):
elif isinstance(prop, (ComparableProperty, SynonymProperty)) and setparent:
if prop.descriptor is None:
- prop.descriptor = getattr(self.class_, key, None)
- if isinstance(prop.descriptor, Mapper._CompileOnAttr):
- prop.descriptor = object.__getattribute__(prop.descriptor, 'existing_prop')
+ desc = getattr(self.class_, key, None)
+ if isinstance(desc, Mapper._CompileOnAttr):
+ desc = object.__getattribute__(desc, 'existing_prop')
+ if self._is_userland_descriptor(desc):
+ prop.descriptor = desc
if getattr(prop, 'map_column', False):
if key not in self.mapped_table.c:
raise sa_exc.ArgumentError("Can't compile synonym '%s': no column on table '%s' named '%s'" % (prop.name, self.mapped_table.description, key))
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 3d717cae0..ceabc2792 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -41,7 +41,7 @@ class ColumnProperty(StrategizedProperty):
self.columns = [expression._labeled(c) for c in columns]
self.group = kwargs.pop('group', None)
self.deferred = kwargs.pop('deferred', False)
- self.comparator_factory = ColumnProperty.ColumnComparator
+ self.comparator_factory = kwargs.pop('comparator_factory', ColumnProperty.ColumnComparator)
util.set_creation_order(self)
if self.deferred:
self.strategy_class = strategies.DeferredColumnLoader
@@ -161,10 +161,11 @@ class CompositeProperty(ColumnProperty):
return str(self.parent.class_.__name__) + "." + self.key
class SynonymProperty(MapperProperty):
- def __init__(self, name, map_column=None, descriptor=None):
+ def __init__(self, name, map_column=None, descriptor=None, comparator_factory=None):
self.name = name
self.map_column = map_column
self.descriptor = descriptor
+ self.comparator_factory = comparator_factory
util.set_creation_order(self)
def setup(self, context, entity, path, adapter, **kwargs):
@@ -192,10 +193,14 @@ class SynonymProperty(MapperProperty):
def comparator_callable(prop, mapper):
def comparator():
prop = self.parent._get_property(self.key, resolve_synonyms=True)
- return prop.comparator_factory(prop, mapper)
+ if self.comparator_factory:
+ return self.comparator_factory(prop, mapper)
+ else:
+ return prop.comparator_factory(prop, mapper)
return comparator
- strategies.DefaultColumnLoader(self)._register_attribute(None, None, False, comparator_callable, proxy_property=self.descriptor)
+ strategies.DefaultColumnLoader(self)._register_attribute(
+ None, None, False, comparator_callable, proxy_property=self.descriptor)
def merge(self, session, source, dest, dont_load, _recursive):
pass