From: Mike Bayer Date: Sat, 25 Mar 2006 02:25:59 +0000 (+0000) Subject: got some support for mapping to a select that only selects some of the columns of... X-Git-Tag: rel_0_1_5~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34d961cde0267f472850f2ceb09b3733033c62d6;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git got some support for mapping to a select that only selects some of the columns of an underlying table --- diff --git a/examples/polymorph/polymorph2.py b/examples/polymorph/polymorph2.py index 99ee6c34c9..eebac80c18 100644 --- a/examples/polymorph/polymorph2.py +++ b/examples/polymorph/polymorph2.py @@ -94,8 +94,6 @@ class PersonLoader(MapperExtension): return False else: return True - - people_mapper = mapper(Person, person_join, extension=PersonLoader()) diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py index 5b56358bae..907d412faa 100644 --- a/lib/sqlalchemy/mapping/mapper.py +++ b/lib/sqlalchemy/mapping/mapper.py @@ -18,6 +18,11 @@ import weakref # a dictionary mapping classes to their primary mappers mapper_registry = weakref.WeakKeyDictionary() +# a constant returned by _getattrbycolumn to indicate +# this mapper is not handling an attribute for a particular +# column +NO_ATTRIBUTE = object() + class Mapper(object): """Persists object instances to and from schema.Table objects via the sql package. Instances of this class should be constructed through this package's mapper() or @@ -534,19 +539,25 @@ class Mapper(object): params = {} return self.instances(statement.execute(**params), **kwargs) - def _getpropbycolumn(self, column): + def _getpropbycolumn(self, column, raiseerror=True): try: prop = self.columntoproperty[column.original] except KeyError: try: prop = self.props[column.key] + if not raiseerror: + return None raise InvalidRequestError("Column '%s.%s' is not available, due to conflicting property '%s':%s" % (column.table.name, column.name, column.key, repr(prop))) except KeyError: + if not raiseerror: + return None raise InvalidRequestError("No column %s.%s is configured on mapper %s..." % (column.table.name, column.name, str(self))) return prop[0] - def _getattrbycolumn(self, obj, column): - prop = self._getpropbycolumn(column) + def _getattrbycolumn(self, obj, column, raiseerror=True): + prop = self._getpropbycolumn(column, raiseerror) + if prop is None: + return NO_ATTRIBUTE return prop.getattr(obj) def _setattrbycolumn(self, obj, column, value): @@ -615,7 +626,9 @@ class Mapper(object): # doing an UPDATE ? get the history for the attribute, with "passive" # so as not to trigger any deferred loads. if there is a new # value, add it to the bind parameters - prop = self._getpropbycolumn(col) + prop = self._getpropbycolumn(col, False) + if prop is None: + continue history = prop.get_history(obj, passive=True) if history: a = history.added_items() @@ -629,7 +642,9 @@ class Mapper(object): # default. if its None and theres no default, we still might # not want to put it in the col list but SQLIte doesnt seem to like that # if theres no columns at all - value = self._getattrbycolumn(obj, col) + value = self._getattrbycolumn(obj, col, False) + if value is NO_ATTRIBUTE: + continue if col.default is None or value is not None: params[col.key] = value @@ -682,13 +697,16 @@ class Mapper(object): clause.clauses.append(p == self._getattrbycolumn(obj, p)) row = table.select(clause).execute().fetchone() for c in table.c: - if self._getattrbycolumn(obj, c) is None: + if self._getattrbycolumn(obj, c, False) is None: self._setattrbycolumn(obj, c, row[c]) else: for c in table.c: if c.primary_key or not params.has_key(c.name): continue - if self._getattrbycolumn(obj, c) != params.get_original(c.name): + v = self._getattrbycolumn(obj, c, False) + if v is NO_ATTRIBUTE: + continue + elif v != params.get_original(c.name): self._setattrbycolumn(obj, c, params.get_original(c.name)) def delete_obj(self, objects, uow): diff --git a/lib/sqlalchemy/mapping/unitofwork.py b/lib/sqlalchemy/mapping/unitofwork.py index 1e5388933d..fc589f65bb 100644 --- a/lib/sqlalchemy/mapping/unitofwork.py +++ b/lib/sqlalchemy/mapping/unitofwork.py @@ -737,7 +737,7 @@ class UOWTask(object): def _repr_task(task): if task.mapper is not None: if task.mapper.__class__.__name__ == 'Mapper': - name = task.mapper.class_.__name__ + "/" + task.mapper.primarytable.id + "/" + str(id(task.mapper)) + name = task.mapper.class_.__name__ + "/" + str(task.mapper.primarytable) + "/" + str(id(task.mapper)) else: name = repr(task.mapper) else: