diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2006-12-09 04:00:35 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2006-12-09 04:00:35 +0000 |
| commit | f279e2b1f24bd6efc7542707707ea9724f679e65 (patch) | |
| tree | 607fbadf483ba2652b41f4a9881bc0e6a1b55d4a /lib/sqlalchemy | |
| parent | d56a50eb7056cfe054c03b47db3d79dab03a5638 (diff) | |
| download | sqlalchemy-f279e2b1f24bd6efc7542707707ea9724f679e65.tar.gz | |
- added onupdate and ondelete keyword arguments to ForeignKey; propigate
to underlying ForeignKeyConstraint if present. (dont propigate in the
other direction, however)
- patched attribute speed enhancement [ticket:389] courtesy Sébastien Lelong
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 56 | ||||
| -rw-r--r-- | lib/sqlalchemy/schema.py | 6 |
2 files changed, 43 insertions, 19 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 915ccd209..17f909613 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -609,8 +609,19 @@ class AttributeHistory(object): class AttributeManager(object): """allows the instrumentation of object attributes. AttributeManager is stateless, but can be - overridden by subclasses to redefine some of its factory operations.""" - + overridden by subclasses to redefine some of its factory operations. Also be aware AttributeManager + will cache attributes for a given class, allowing not to determine those for each objects (used + in managed_attributes() and noninherited_managed_attributes()). This cache is cleared for a given class + while calling register_attribute(), and can be cleared using clear_attribute_cache()""" + + def __init__(self): + # will cache attributes, indexed by class objects + self._inherited_attribute_cache = weakref.WeakKeyDictionary() + self._noninherited_attribute_cache = weakref.WeakKeyDictionary() + + def clear_attribute_cache(self): + self._attribute_cache.clear() + def rollback(self, *obj): """retrieves the committed history for each object in the given list, and rolls back the attributes each instance to their original value.""" @@ -636,24 +647,28 @@ class AttributeManager(object): for o in obj: o._state['original'] = CommittedState(self, o) o._state['modified'] = False - + def managed_attributes(self, class_): """returns an iterator of all InstrumentedAttribute objects associated with the given class.""" - if not isinstance(class_, type): - raise repr(class_) + " is not a type" - for key in dir(class_): - value = getattr(class_, key, None) - if isinstance(value, InstrumentedAttribute): - yield value + try: + return self._inherited_attribute_cache[class_] + except KeyError: + if not isinstance(class_, type): + raise TypeError(repr(class_) + " is not a type") + inherited = [v for v in [getattr(class_, key, None) for key in dir(class_)] if isinstance(v, InstrumentedAttribute)] + self._inherited_attribute_cache[class_] = inherited + return inherited def noninherited_managed_attributes(self, class_): - if not isinstance(class_, type): - raise repr(class_) + " is not a type" - for key in list(class_.__dict__): - value = getattr(class_, key, None) - if isinstance(value, InstrumentedAttribute): - yield value - + try: + return self._noninherited_attribute_cache[class_] + except KeyError: + if not isinstance(class_, type): + raise TypeError(repr(class_) + " is not a type") + noninherited = [v for v in [getattr(class_, key, None) for key in list(class_.__dict__)] if isinstance(v, InstrumentedAttribute)] + self._noninherited_attribute_cache[class_] = noninherited + return noninherited + def is_modified(self, object): for attr in self.managed_attributes(object.__class__): if attr.check_mutable_modified(object): @@ -714,7 +729,9 @@ class AttributeManager(object): """removes all InstrumentedAttribute property objects from the given class.""" for attr in self.noninherited_managed_attributes(class_): delattr(class_, attr.key) - + self._inherited_attribute_cache.pop(class_,None) + self._noninherited_attribute_cache.pop(class_,None) + def is_class_managed(self, class_, key): """returns True if the given key correponds to an instrumented property on the given class.""" return hasattr(class_, key) and isinstance(getattr(class_, key), InstrumentedAttribute) @@ -733,6 +750,11 @@ class AttributeManager(object): def register_attribute(self, class_, key, uselist, callable_=None, **kwargs): """registers an attribute at the class level to be instrumented for all instances of the class.""" + # firt invalidate the cache for the given class + # (will be reconstituted as needed, while getting managed attributes) + self._inherited_attribute_cache.pop(class_,None) + self._noninherited_attribute_cache.pop(class_,None) + #print self, "register attribute", key, "for class", class_ if not hasattr(class_, '_state'): def _get_state(self): diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 8ebeaea27..93f4574bc 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -501,7 +501,7 @@ class ForeignKey(SchemaItem): One or more ForeignKey objects are used within a ForeignKeyConstraint object which represents the table-level constraint definition.""" - def __init__(self, column, constraint=None, use_alter=False, name=None): + def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None): """Construct a new ForeignKey object. "column" can be a schema.Column object representing the relationship, @@ -518,6 +518,8 @@ class ForeignKey(SchemaItem): self.constraint = constraint self.use_alter = use_alter self.name = name + self.onupdate = onupdate + self.ondelete = ondelete def __repr__(self): return "ForeignKey(%s)" % repr(self._get_colspec()) @@ -588,7 +590,7 @@ class ForeignKey(SchemaItem): self.parent = column if self.constraint is None and isinstance(self.parent.table, Table): - self.constraint = ForeignKeyConstraint([],[], use_alter=self.use_alter, name=self.name) + self.constraint = ForeignKeyConstraint([],[], use_alter=self.use_alter, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete) self.parent.table.append_constraint(self.constraint) self.constraint._append_fk(self) |
