diff options
author | Jason Kirtland <jek@discorporate.us> | 2007-08-01 01:44:24 +0000 |
---|---|---|
committer | Jason Kirtland <jek@discorporate.us> | 2007-08-01 01:44:24 +0000 |
commit | cd2176d48d3996dabbc44205ff7cee344b30248f (patch) | |
tree | 7b37273ae649006b8ba807d843c55b2514d9d7a2 | |
parent | ed6e7c3896ff33db876e15b3f20bc8494af74a7a (diff) | |
download | sqlalchemy-cd2176d48d3996dabbc44205ff7cee344b30248f.tar.gz |
It's now possible to map only a subset of available selectable columns onto mapper properties [ticket:696].
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/__init__.py | 14 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 60 | ||||
-rw-r--r-- | test/orm/mapper.py | 51 |
4 files changed, 105 insertions, 23 deletions
@@ -132,6 +132,9 @@ a column- level "deferred" load, via the "polymorphic_fetch" argument, which can be set to 'select' or 'deferred' + - it's now possible to map only a subset of available selectable columns + onto mapper properties [ticket:696]. + - added undefer_group() MapperOption, sets a set of "deferred" columns joined by a "group" to load as "undeferred". diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index 3d8461dfd..66c4d796e 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -429,6 +429,20 @@ def mapper(class_, local_table=None, *args, **params): each ``Column`` (although they can be overridden using this dictionary). + include_properties + An inclusive list of properties to map. Columns present in the + mapped table but not present in this list will not be automatically + converted into properties. + + exclude_properties + A list of properties not to map. Columns present in the + mapped table and present in this list will not be automatically + converted into properties. Note that neither this option nor + include_properties will allow an end-run around Python inheritance. + If mapped class ``B`` inherits from mapped class ``A``, no combination + of includes or excludes will allow ``B`` to have fewer properties + than its superclass, ``A``. + primary_key A list of ``Column`` objects which define the *primary key* to be used against this mapper's selectable unit. This is diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index c96b3be22..6706b07e4 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -41,28 +41,30 @@ class Mapper(object): """ def __init__(self, - class_, - local_table, - properties = None, - primary_key = None, - non_primary = False, - inherits = None, - inherit_condition = None, - extension = None, - order_by = False, - allow_column_override = False, - entity_name = None, - always_refresh = False, - version_id_col = None, - polymorphic_on=None, - _polymorphic_map=None, - polymorphic_identity=None, - polymorphic_fetch=None, - concrete=False, - select_table=None, - allow_null_pks=False, - batch=True, - column_prefix=None): + class_, + local_table, + properties = None, + primary_key = None, + non_primary = False, + inherits = None, + inherit_condition = None, + extension = None, + order_by = False, + allow_column_override = False, + entity_name = None, + always_refresh = False, + version_id_col = None, + polymorphic_on=None, + _polymorphic_map=None, + polymorphic_identity=None, + polymorphic_fetch=None, + concrete=False, + select_table=None, + allow_null_pks=False, + batch=True, + column_prefix=None, + include_properties=None, + exclude_properties=None): """Construct a new mapper. Mappers are normally constructed via the [sqlalchemy.orm#mapper()] @@ -137,6 +139,9 @@ class Mapper(object): self.columns = LOrderedProp() self.c = self.columns + self.include_properties = include_properties + self.exclude_properties = exclude_properties + # each time the options() method is called, the resulting Mapper is # stored in this dictionary based on the given options for fast re-access self._options = {} @@ -577,7 +582,18 @@ class Mapper(object): column_key = (self.column_prefix or '') + column.key prop = self.__props.get(column.key, None) + if prop is None: + if (self.include_properties is not None and + column_key not in self.include_properties): + self.__log("not including property %s" % (column_key)) + continue + + if (self.exclude_properties is not None and + column_key in self.exclude_properties): + self.__log("excluding property %s" % (column_key)) + continue + prop = ColumnProperty(column) self.__props[column_key] = prop prop.set_parent(self) diff --git a/test/orm/mapper.py b/test/orm/mapper.py index 414a1936f..5bb33b241 100644 --- a/test/orm/mapper.py +++ b/test/orm/mapper.py @@ -241,7 +241,56 @@ class MapperTest(MapperSuperTest): 'addresses' : relation(mapper(Address, addresses)) }).compile() self.assert_(User.addresses.property is m.get_property('addresses')) - + + def testpropfilters(self): + t = Table('person', MetaData(), + Column('id', Integer, primary_key=True), + Column('type', String), + Column('name', String), + Column('employee_number', Integer), + Column('boss_id', Integer, ForeignKey('person.id')), + Column('vendor_id', Integer)) + + class Person(object): pass + class Vendor(Person): pass + class Employee(Person): pass + class Manager(Employee): pass + class Hoho(object): pass + class Lala(object): pass + + p_m = mapper(Person, t, polymorphic_on=t.c.type, + include_properties=('id', 'type', 'name')) + e_m = mapper(Employee, inherits=p_m, polymorphic_identity='employee', + properties={ + 'boss': relation(Manager, backref='peon') + }, + exclude_properties=('vendor_id',)) + + m_m = mapper(Manager, inherits=e_m, polymorphic_identity='manager', + include_properties=()) + + v_m = mapper(Vendor, inherits=p_m, polymorphic_identity='vendor', + exclude_properties=('boss_id', 'employee_number')) + h_m = mapper(Hoho, t, include_properties=('id', 'type', 'name')) + l_m = mapper(Lala, t, exclude_properties=('vendor_id', 'boss_id')) + + for m in p_m, e_m, m_m, v_m, h_m, l_m: + m.compile() + + def assert_props(cls, want): + have = set([n for n in dir(cls) if not n.startswith('_')]) + want = set(want) + want.add('c') + self.assert_(have == want) + + assert_props(Person, ['id', 'name', 'type']) + assert_props(Employee, ['boss', 'boss_id', 'employee_number', + 'id', 'name', 'type']) + assert_props(Manager, ['boss', 'boss_id', 'employee_number', 'peon', + 'id', 'name', 'type']) + assert_props(Vendor, ['vendor_id', 'id', 'name', 'type']) + assert_props(Hoho, ['id', 'name', 'type']) + assert_props(Lala, ['employee_number', 'id', 'name', 'type']) def testrecursiveselectby(self): """test that no endless loop occurs when traversing for select_by""" |