On Feb 15, 2008, at 11:21 PM, Eric Ongerth wrote:
>
> In case I didn't make it clear enough -- I've already done the
> following:
>
> 'children': relation(Bar,
> collection_class=attribute_mapped_collection('foo'),
> backref=backref('parent', remote_side=[bars.c.id])) } )
>
> And that worked great -- if I only needed to have up to a SINGLE child
> per bar per foo. Because the dict in attribute_mapped_collection
> expects scalar keys and scalar values, right? It's not set up to
> collect a whole list of values per key. And that is what I need. Any
> given Foo is only going to appear once in the keys of any given Bar's
> children DictOfLists, of course. But the values mapped to that given
> Foo need to be a list of Bars of any length. Any given Bar will have
> 1..n children in the bars table; each of these child Bars will be
> related to a single Foo, but the total number of Foos is < n, so a
> parent Bar might have a number of child Bars for a given Foo, while
> only having zero or one single child Bar for some other Foo.
>
> There, I think that tells it more completely. Sorry for the
> metasyntactic variables.
Im not sure you're going to be able to use the collection classes here
- those are all built on the notion of mapped elements being
"appended" and "removed" from a collection.....but here you are
appending and removing further subsets of elements. Its possible that
you could define @appender and @remover methods that deal with the
simple row-based data but then expose the dictionary methods in such a
way as to group things into lists and such but i dont see how the
collection classes really help here, they seem to be an unnecessary
complexity since you really have to build an entire "adaptation" layer
over the raw data. These layers are actually quite easy to build once
you accept that you have to do it.
My approach is below, and is my style it keeps the ORM side of things
completely simple - the "dict of lists" "view" of the data is built up
entirely using Python attribute and collection customizations, all
interpreting against a simple collection of elements. With this
approach I'd want to build up a good suite of 20-30 unit tests to
ensure all the expected dict/list operations are working properly.
from sqlalchemy import *
from sqlalchemy.orm import *
metadata = MetaData()
objects = Table('objects', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50), nullable=False)
)
object_dict_of_lists = Table('object_dict_of_lists', metadata,
Column('id', Integer, primary_key=True),
Column('object_id', Integer, ForeignKey('objects.id')),
Column('key', String(50), nullable=False),
Column('data', String(50), nullable=False)
)
engine = create_engine("sqlite:///:memory:", echo=True)
metadata.bind = engine
metadata.create_all()
class Object(object):
def __init__(self, name, data=None):
self.name = name
if data:
self.data = data
class DictOfListElement(object):
def __init__(self, key, data):
self.key = key
self.data = data
mapper(Object, objects, properties={
'_data':relation(DictOfListElement)
})
mapper(DictOfListElement, object_dict_of_lists)
class ListAdapter(object):
def __init__(self, parent, key):
self.__parent = parent
self.__key = key
def __cached(self):
try:
return self.__cached_data
except AttributeError:
self.__cached_data = [item.data for item in
self.__parent._data if item.key == self.__key]
return self.__cached_data
__cached = property(__cached)
def __iter__(self):
return iter(self.__cached)
def __eq__(self, other):
return list(self) == list(other)
def __repr__(self):
return repr(list(self))
def append(self, item):
self.__parent._data.append(DictOfListElement(self.__key, item))
self.__cached.append(item)
def __getitem__(self, index):
return self.__cached[index]
def __setitem__(self, index, value):
self.__cached[index].data = value
# other list like methods
class DictAdapterAttribute(object):
def __get__(self, instance, owner):
if instance is None:
return self
class DictAdapter(object):
def __getitem__(self, key):
return ListAdapter(instance, key)
def keys(self):
return iter(set([item.key for item in instance._data]))
def __eq__(self, other):
return dict(self) == dict(other)
def __repr__(self):
return repr(dict(self))
# other dict like methods
return DictAdapter()
def __set__(self, instance, somedict):
l =[]
for key, somelist in somedict.items():
for item in somelist:
l.append(DictOfListElement(key, item))
instance._data = l
Object.data = DictAdapterAttribute()
sess = create_session()
obj1 = Object('object1', {
'key1':['key1_one', 'key1_two', 'key1_three'],
'key2':['key2_one', 'key2_two', 'key2_three'],
'key3':['key3_one', 'key3_two', 'key3_three'],
})
sess.save(obj1)
sess.flush()
sess.clear()
obj1 = sess.query(Object).get(obj1.id)
assert obj1.data['key2'] == ['key2_one', 'key2_two', 'key2_three'],
obj1.data['key2']
obj1.data['key3'].append('key3_four')
sess.flush()
sess.clear()
obj1 = sess.query(Object).get(obj1.id)
assert obj1.data == {
'key1':['key1_one', 'key1_two', 'key1_three'],
'key2':['key2_one', 'key2_two', 'key2_three'],
'key3':['key3_one', 'key3_two', 'key3_three', 'key3_four'],
}
print obj1.data
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---