"instrument" keyword argument, e.g.: somekey =
synonym('_somekey', instrument=property(g, s))
+ - Declarative also gained @synonym_for(...) and
+ @comparable_using(...), front-ends for synonym and
+ comparable_property.
+
0.4.4
------
- sql
x = MyClass()
x.attr = "some value"
session.query(MyClass).filter(MyClass.attr == 'some other value').all()
+
+The `synonyn_for` decorator can accomplish the same task:
+
+ {python}
+ class MyClass(Base):
+ __tablename__ = 'sometable'
+ _attr = Column('attr', String)
+
+ @synonyn_for('_attr')
+ @property
+ def attr(self):
+ return self._some_attr
+
+Similarly, `comparable_using` is a front end for the `comparable_property` ORM function:
+
+ {python}
+ class MyClass(Base):
+ __tablename__ = 'sometable'
+
+ name = Column('name', String)
+
+ @comparable_using(MyUpperCaseComparator)
+ @property
+ def uc_name(self):
+ return self.name.upper()
+
As an alternative to `__tablename__`, a direct `Table` construct may be used:
{python}
"""
from sqlalchemy.schema import Table, SchemaItem, Column, MetaData
-from sqlalchemy.orm import synonym as _orm_synonym, mapper
+from sqlalchemy.orm import synonym as _orm_synonym, mapper, comparable_property
from sqlalchemy.orm.interfaces import MapperProperty
from sqlalchemy.orm.properties import PropertyLoader
from sqlalchemy import util
-__all__ = ['declarative_base', 'declared_synonym']
+__all__ = ['declarative_base', 'synonym_for', 'comparable_using',
+ 'declared_synonym']
class DeclarativeMeta(type):
def __init__(cls, classname, bases, dict_):
return _orm_synonym(name, instrument=prop)
declared_synonym = util.deprecated(declared_synonym)
-
+
+def synonym_for(name, map_column=False):
+ """Decorator, make a Python @property a query synonym for a column.
+
+ A decorator version of [sqlalchemy.orm#synonym()]. The function being
+ decoratred is the 'instrument', otherwise passes its arguments through
+ to synonym().
+
+ @synonym_for('col')
+ @property
+ def prop(self):
+ return 'special sauce'
+
+ The regular ``synonym()`` is also usable directly in a declarative
+ setting and may be convenient for read/write properties::
+
+ prop = synonym('col', instrument=property(_read_prop, _write_prop))
+
+ """
+ def decorate(fn):
+ return _orm_synonym(name, map_column=map_column, instrument=fn)
+ return decorate
+
+
+def comparable_using(comparator_factory):
+ """Decorator, allow a Python @property to be used in query criteria.
+
+ A decorator front end to [sqlalchemy.orm#comparable_property()], passes
+ throgh the comparator_factory and the function being decorated.
+
+ @comparable_using(MyComparatorType)
+ @property
+ def prop(self):
+ return 'special sauce'
+
+ The regular ``comparable_property()`` is also usable directly in a
+ declarative setting and may be convenient for read/write properties::
+
+ prop = comparable_property(MyComparatorType)
+ """
+ def decorate(fn):
+ return comparable_property(comparator_factory, fn)
+ return decorate
+
def declarative_base(engine=None, metadata=None):
lcl_metadata = metadata or MetaData()
class Base(object):
from sqlalchemy import *
from sqlalchemy.orm import *
-from sqlalchemy.ext.declarative import declarative_base, declared_synonym
+from sqlalchemy.ext.declarative import declarative_base, declared_synonym, \
+ synonym_for, comparable_using
from sqlalchemy import exceptions
from testlib.fixtures import Base as Fixture
from testlib import *
self.assertEquals(a1, IMHandle(network='lol', handle='zomg'))
self.assertEquals(a1.user, User(name='u1'))
+ def test_synonym_for(self):
+ class User(Base, Fixture):
+ __tablename__ = 'users'
+
+ id = Column('id', Integer, primary_key=True)
+ name = Column('name', String(50))
+
+ @synonym_for('name')
+ @property
+ def namesyn(self):
+ return self.name
+
+ Base.metadata.create_all()
+
+ sess = create_session()
+ u1 = User(name='someuser')
+ assert u1.name == "someuser", u1.name
+ assert u1.namesyn == 'someuser', u1.namesyn
+ sess.save(u1)
+ sess.flush()
+
+ rt = sess.query(User).filter(User.namesyn=='someuser').one()
+ self.assertEquals(rt, u1)
+
+ def test_comparable_using(self):
+ class NameComparator(PropComparator):
+ @property
+ def upperself(self):
+ cls = self.prop.parent.class_
+ col = getattr(cls, 'name')
+ return func.upper(col)
+
+ def operate(self, op, other, **kw):
+ return op(self.upperself, other, **kw)
+
+ class User(Base, Fixture):
+ __tablename__ = 'users'
+
+ id = Column('id', Integer, primary_key=True)
+ name = Column('name', String(50))
+
+ @comparable_using(NameComparator)
+ @property
+ def uc_name(self):
+ return self.name is not None and self.name.upper() or None
+
+ Base.metadata.create_all()
+
+ sess = create_session()
+ u1 = User(name='someuser')
+ assert u1.name == "someuser", u1.name
+ assert u1.uc_name == 'SOMEUSER', u1.uc_name
+ sess.save(u1)
+ sess.flush()
+ sess.clear()
+
+ rt = sess.query(User).filter(User.uc_name=='SOMEUSER').one()
+ self.assertEquals(rt, u1)
+ sess.clear()
+
+ rt = sess.query(User).filter(User.uc_name.startswith('SOMEUSE')).one()
+ self.assertEquals(rt, u1)
+
if __name__ == '__main__':
testing.main()