a flush() under some circumstances, this was fixed
- expunge() was not working with cascade, fixed.
- potential endless loop in cascading operations fixed.
+- added "synonym()" function, applied to properties to have a
+propname the same as another, for the purposes of overriding props
+and allowing the original propname to be accessible in select_by().
0.2.5
- fixed endless loop bug in select_by(), if the traversal hit
'_email': mytable.c.email
})
-In a later release, SQLAlchemy will also allow `_get_email` and `_set_email` to be attached directly to the "email" property created by the mapper, and
-will also allow this association to occur via decorators.
+It is also possible to use the `select_by` and `get_by` functions on `Query` using the original property name, by establishing a `synonym`:
+ {python}
+ mapper(MyClass, mytable, proeprties = {
+ # map the '_email' attribute to the "email" column
+ # on the table
+ '_email': mytable.c.email
+
+ # make a synonym 'email'
+ 'email' : synonym('_email')
+ })
+
+ # now you can select_by(email)
+ result = session.query(MyClass).select_by(email='john@smith.com')
+
+The `synonym` keyword is currently an [Alpha Feature][alpha_api].
#### Custom List Classes {@name=customlist}
__all__ = ['relation', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer',
'mapper', 'clear_mappers', 'sql', 'extension', 'class_mapper', 'object_mapper', 'MapperExtension', 'Query',
- 'cascade_mappers', 'polymorphic_union', 'create_session', 'EXT_PASS'
+ 'cascade_mappers', 'polymorphic_union', 'create_session', 'synonym', 'EXT_PASS'
]
def relation(*args, **kwargs):
"""returns a newMapper object."""
return Mapper(class_, table, *args, **params)
+def synonym(name):
+ return SynonymProperty(name)
+
def clear_mappers():
"""removes all mappers that have been created thus far. when new mappers are
created, they will be assigned to their classes as their primary mapper."""
import session as sessionlib
import weakref
-__all__ = ['Mapper', 'MapperExtension', 'class_mapper', 'object_mapper', 'EXT_PASS']
+__all__ = ['Mapper', 'MapperExtension', 'class_mapper', 'object_mapper', 'SynonymProperty', 'EXT_PASS']
# a dictionary mapping classes to their primary mappers
mapper_registry = weakref.WeakKeyDictionary()
at the class level. otherwise we have to set attribute behavior on a per-instance level."""
return self.parent._is_primary_mapper()
+class SynonymProperty(MapperProperty):
+ """a marker object used by query.select_by to allow a property name to refer to another.
+
+ this object may be expanded in the future."""
+ def __init__(self, name):
+ self.name = name
+ def execute(self, session, instance, row, identitykey, imap, isnew):
+ pass
+ def copy(self):
+ return SynonymProperty(self.name)
+
class MapperOption(object):
"""describes a modification to a Mapper in the context of making a copy
of it. This is used to assist in the prototype pattern used by mapper.options()."""
import properties
keys = []
seen = util.Set()
- def search_for_prop(mapper):
- if mapper in seen:
+ def search_for_prop(mapper_):
+ if mapper_ in seen:
return None
- seen.add(mapper)
- if mapper.props.has_key(key):
- prop = mapper.props[key]
+ seen.add(mapper_)
+ if mapper_.props.has_key(key):
+ prop = mapper_.props[key]
+ if isinstance(prop, mapper.SynonymProperty):
+ prop = mapper_.props[prop.name]
if isinstance(prop, properties.PropertyLoader):
keys.insert(0, prop.key)
return prop
else:
- for prop in mapper.props.values():
+ for prop in mapper_.props.values():
if not isinstance(prop, properties.PropertyLoader):
continue
x = search_for_prop(prop.mapper)