1
"""this example illustrates how to replace SQLAlchemy's class descriptors with
4
This sort of thing is appropriate for integration with frameworks that
5
redefine class behaviors in their own way, such that SQLA's default
6
instrumentation is not compatible.
8
The example illustrates redefinition of instrumentation at the class level as
9
well as the collection level, and redefines the storage of the class to store
10
state within "instance._goofy_dict" instead of "instance.__dict__". Note that
11
the default collection implementations can be used with a custom attribute
1
"""Illustrates customized class instrumentation, using
2
the :mod:`sqlalchemy.ext.instrumentation` extension package.
4
In this example, mapped classes are modified to
5
store their state in a dictionary attached to an attribute
6
named "_goofy_dict", instead of using __dict__.
7
this example illustrates how to replace SQLAlchemy's class
8
descriptors with a user-defined system.
15
12
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, Text,\
17
from sqlalchemy.orm import mapper, relationship, Session,\
18
InstrumentationManager
14
from sqlalchemy.orm import mapper, relationship, Session
20
16
from sqlalchemy.orm.attributes import set_attribute, get_attribute, \
22
18
from sqlalchemy.orm.instrumentation import is_instrumented
23
from sqlalchemy.orm.collections import collection_adapter
20
from sqlalchemy.ext.instrumentation import InstrumentationManager
26
22
class MyClassState(InstrumentationManager):
27
def __init__(self, cls):
30
def instrument_attribute(self, class_, key, attr):
33
def install_descriptor(self, class_, key, attr):
36
def uninstall_descriptor(self, class_, key, attr):
39
def instrument_collection_class(self, class_, key, collection_class):
42
23
def get_instance_dict(self, class_, instance):
43
24
return instance._goofy_dict
45
26
def initialize_instance_dict(self, class_, instance):
46
27
instance.__dict__['_goofy_dict'] = {}
48
def initialize_collection(self, key, state, factory):
50
return MyCollectionAdapter(key, state, data), data
52
29
def install_state(self, class_, instance, state):
53
self.states[id(instance)] = state
30
instance.__dict__['_goofy_dict']['state'] = state
55
32
def state_getter(self, class_):
56
33
def find(instance):
57
return self.states[id(instance)]
34
return instance.__dict__['_goofy_dict']['state']
60
37
class MyClass(object):
86
63
del self._goofy_dict[key]
88
class MyCollectionAdapter(object):
89
"""An wholly alternative instrumentation implementation."""
91
def __init__(self, key, state, collection):
94
self.collection = collection
95
setattr(collection, '_sa_adapter', self)
97
def unlink(self, data):
98
setattr(data, '_sa_adapter', None)
100
def adapt_like_to_iterable(self, obj):
103
def append_with_event(self, item, initiator=None):
104
self.collection.add(item, emit=initiator)
106
def append_multiple_without_event(self, items):
107
self.collection.members.extend(items)
109
def append_without_event(self, item):
110
self.collection.add(item, emit=False)
112
def remove_with_event(self, item, initiator=None):
113
self.collection.remove(item, emit=initiator)
115
def remove_without_event(self, item):
116
self.collection.remove(item, emit=False)
118
def clear_with_event(self, initiator=None):
119
for item in list(self):
120
self.remove_with_event(item, initiator)
121
def clear_without_event(self):
122
for item in list(self):
123
self.remove_without_event(item)
125
return iter(self.collection)
127
def fire_append_event(self, item, initiator=None):
128
if initiator is not False and item is not None:
129
self.state.get_impl(self.key).\
130
fire_append_event(self.state, self.state.dict, item,
133
def fire_remove_event(self, item, initiator=None):
134
if initiator is not False and item is not None:
135
self.state.get_impl(self.key).\
136
fire_remove_event(self.state, self.state.dict, item,
139
def fire_pre_remove_event(self, initiator=None):
140
self.state.get_impl(self.key).\
141
fire_pre_remove_event(self.state, self.state.dict,
144
class MyCollection(object):
146
self.members = list()
147
def add(self, object, emit=None):
148
self.members.append(object)
149
collection_adapter(self).fire_append_event(object, emit)
150
def remove(self, object, emit=None):
151
collection_adapter(self).fire_pre_remove_event(object)
152
self.members.remove(object)
153
collection_adapter(self).fire_remove_event(object, emit)
154
def __getitem__(self, index):
155
return self.members[index]
157
return iter(self.members)
159
return len(self.members)
161
66
if __name__ == '__main__':
162
meta = MetaData(create_engine('sqlite://'))
67
engine = create_engine('sqlite://')
164
70
table1 = Table('table1', meta,
165
71
Column('id', Integer, primary_key=True),