From: Mike Bayer Date: Sun, 26 Dec 2010 22:28:56 +0000 (-0500) Subject: - docs for mutable events example X-Git-Tag: rel_0_7b1~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e58059cbba6f612a86a9d03583e30717bcdd6c4;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - docs for mutable events example --- diff --git a/doc/build/orm/examples.rst b/doc/build/orm/examples.rst index 00b18bc7b8..bf3ede6d49 100644 --- a/doc/build/orm/examples.rst +++ b/doc/build/orm/examples.rst @@ -87,6 +87,13 @@ Location: /examples/large_collection/ .. automodule:: large_collection +Mutable Data Types +------------------ + +Location: /examples/mutable_events/ + +.. automodule:: mutable_events + Nested Sets ----------- diff --git a/examples/mutable_events/__init__.py b/examples/mutable_events/__init__.py index 813dc5abd2..3b6363b966 100644 --- a/examples/mutable_events/__init__.py +++ b/examples/mutable_events/__init__.py @@ -1,14 +1,36 @@ """ Illustrates how to build and use "mutable" types, such as dictionaries and user-defined classes, as scalar attributes which detect in-place changes. +These types don't make use of the "mutable=True" flag, which +performs poorly within the ORM and is being phased out, instead allowing +changes on data to associate change events with the parent object +as they happen in the same way as any other mapped data member. The example is based around the usage of the event model introduced in -:ref:`event_toplevel`, along with the :func:`attributes.flag_modified` function +:ref:`event_toplevel`, along with the :func:`~.attributes.flag_modified` function which establishes the "dirty" flag on a particular mapped attribute. These functions are encapsulated in a mixin called ``TrackMutationsMixin``. -Subclassing ``dict`` to provide "mutation tracking" looks like:: +Subclassing ``dict`` to provide "mutation tracking", then +applying it to a custom dictionary type, looks like:: + + class JSONEncodedDict(TypeDecorator): + "JSON dictionary type from the types documentation" + + impl = VARCHAR + + def process_bind_param(self, value, dialect): + if value is not None: + value = simplejson.dumps(value, use_decimal=True) + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = simplejson.loads(value, use_decimal=True) + return value class MutationDict(TrackMutationsMixin, dict): + "Subclass dict to send mutation events to the owning object." + def __init__(self, other): self.update(other) @@ -20,17 +42,21 @@ Subclassing ``dict`` to provide "mutation tracking" looks like:: dict.__delitem__(self, key) self.on_change() + # hypothetical mapping Base = declarative_base() class Foo(Base): __tablename__ = 'foo' id = Column(Integer, primary_key=True) data = Column(JSONEncodedDict) + # add mutation tracking to `Foo.data` as a one off MutationDict.associate_with_attribute(Foo.data) The explicit step of associating ``MutationDict`` with ``Foo.data`` can be automated across a class of columns using ``associate_with_type()``:: + # add mutation tracking to all mapped attributes + # that use JSONEncodedDict MutationDict.associate_with_type(JSONEncodedDict) All subsequent mappings will have the ``MutationDict`` wrapper applied to