[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
oh, heres a second version that fixes list.__setitem__. the operations here are not terribly efficient but you could build better caching scenarios if needed. 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): [item for item in self.__parent._data if item.key == self.__key][index].data = value self.__cached[index] = 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') obj1.data['key2'][1] = 'key2_two_modified' 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_modified', '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 sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
yet another adjustment to ListAdapter... 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 __delcached(self): try: del self.__cached_data except AttributeError: pass 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.__delcached() self.__parent._data.append(DictOfListElement(self.__key, item)) def __getitem__(self, index): return self.__cached[index] def __setitem__(self, index, value): self.__delcached() [item for item in self.__parent._data if item.key == self.__key][index].data = value # other list like methods --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
also, it would take a lot more experimentation but maybe the @appender and @remover methods could be useful here, just so that the cached view of the data can be maintained as the data is retrieved from the DB.Maybe its just my thought process (also since i didnt write the collections classes) to do it entirely in-Python first, then look for deeper ORM integration second (i.e. actually use collection_class to make the approach more efficient). --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
It occurs to me that a near analogue to this would be... storing a collection of one man's children by different mothers. While it's somewhat useful to have a collection of the guy's children... what if you want to look up his children by just one mother, or by each mother in turn. There's an easy workaround, just looking up the list of his children then asking each child whom its mother is. But that's not nearly as efficient as having his children collection indexed by mother. That's basically all I'm trying to do here (though totally not the problem domain i'm working in!) Thanks again. On Feb 16, 2:23 pm, Eric Ongerth [EMAIL PROTECTED] wrote: Awesome -- Mike, that's a heck of a great response and I'll try it all out. But one quick reply to your very first comment, before I go out and do so. You wrote: quote 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. /quote Actually, I don't need or want the ability to append or remove entire subsets. There will only be a single element appended or removed at a time. It's just that when a Bar is added to one of these children collections, I want it to be filed under a dict slot whose key happens to be the Bar's parent attribute. It should join all the other elements stored in a list which holds the contents of that dict slot. Know what I mean? Similarly, when I remove a Bar from one of these children collections, we look at its parent attribute to determine which slot in the collection it should be removed from, then it gets removed from the list which holds the contents of that dict slot. (Sorry, nonstandard use of the word slot here, just to avoid any ambiguity in using the word value to speak of what's on the right side of the colon in a dict entry). My guess is that making this clear, changes your idea of what I'm trying to achieve. Let me know if that's the case. If not, I need to read more deeply into what you wrote. In either case I'm going to try out your examples. Thanks a bundle for the length and quality of response. On Feb 16, 2:03 pm, Michael Bayer [EMAIL PROTECTED] wrote: yet another adjustment to ListAdapter... 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 __delcached(self): try: del self.__cached_data except AttributeError: pass 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.__delcached() self.__parent._data.append(DictOfListElement(self.__key, item)) def __getitem__(self, index): return self.__cached[index] def __setitem__(self, index, value): self.__delcached() [item for item in self.__parent._data if item.key == self.__key][index].data = value # other list like methods --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
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. On Feb 15, 8:13 pm, Eric Ongerth [EMAIL PROTECTED] wrote: If anyone out there has already implemented a custom DictOfLists collection class to map scalar keys to lists of values, I would be grateful for the opportunity to avoid reinventing the wheel. If not, I guess I'll start working on it. I've experimented successfully with attribute_mapped_collection and column_mapped_collection and they work just great. However, instead of mapping keys to single values, I need some of my mapper relations to map to a list of values. Here is more of the picture, for example. foos = Table('foos', metadata, Column('id', Integer, primary_key=True), Column('name', String(20))) bars = Table('bars', metadata, Column('id', Integer, primary_key=True), Column('foo_id', Integer, ForeignKey('foos.id')), Column('value', String(20)), Column('parent_id', Integer, ForeignKey('bars.id'))) class Foo(object): pass class Bar(object): pass mapper(Foo, foos) mapper(Bar, bars, properties={ 'foo':relation(Foo, uselist=False, backref='bars'), 'children':relation(Bar, backref=backref('parent', remote_side=[bars.c.id])) }) ... So we have a relation of 1 Foo : many Bars. And within the Bars we also have 'adjacency' (tree-like) relations between the various rows of the 'bars' table. A Bar's children are kept in the standard list-like collection class. But what I really need is a *dict* instead of a list. Ok, SA already takes care of that. But I actually need a list-like collection to appear as the value for each key in the dict. Specifically, I need each Bar to be able to have stored children *per Foo*. And not keyed by the parent's foo, but the child's foo. Does that make sense? I'll be working on this immediately, but if anyone can shorten my path to getting this straight I'd be very glad. I'm beginning to work out the use of a custom collection_class for this, but I haven't done all that much with metaclassing and the way forward isn't obvious (the SA instructions about this seem to assume the programmer is pretty experienced with custom subclassing etc.) --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
Ok, I tried subclassing MappedCollection and it seems like I did all right with my made-up appender, remover, and iterator functions. At least I fixed various errors and got this to at least function as the collection_class for the mapper shown above. But I can't figure out how to tell my DictOfLists to return a list instead of a single item. So there's a place where I'm trying to say: for child in some_bar.children[some_foo]: blah(child) etc. Sadly, while some_bar.children[some_foo] at least returns something, it returns a scalar Bar instance, not a list of Bars as I want it too. What's the next step? On Feb 15, 8:21 pm, Eric Ongerth [EMAIL PROTECTED] 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. On Feb 15, 8:13 pm, Eric Ongerth [EMAIL PROTECTED] wrote: If anyone out there has already implemented a custom DictOfLists collection class to map scalar keys to lists of values, I would be grateful for the opportunity to avoid reinventing the wheel. If not, I guess I'll start working on it. I've experimented successfully with attribute_mapped_collection and column_mapped_collection and they work just great. However, instead of mapping keys to single values, I need some of my mapper relations to map to a list of values. Here is more of the picture, for example. foos = Table('foos', metadata, Column('id', Integer, primary_key=True), Column('name', String(20))) bars = Table('bars', metadata, Column('id', Integer, primary_key=True), Column('foo_id', Integer, ForeignKey('foos.id')), Column('value', String(20)), Column('parent_id', Integer, ForeignKey('bars.id'))) class Foo(object): pass class Bar(object): pass mapper(Foo, foos) mapper(Bar, bars, properties={ 'foo':relation(Foo, uselist=False, backref='bars'), 'children':relation(Bar, backref=backref('parent', remote_side=[bars.c.id])) }) ... So we have a relation of 1 Foo : many Bars. And within the Bars we also have 'adjacency' (tree-like) relations between the various rows of the 'bars' table. A Bar's children are kept in the standard list-like collection class. But what I really need is a *dict* instead of a list. Ok, SA already takes care of that. But I actually need a list-like collection to appear as the value for each key in the dict. Specifically, I need each Bar to be able to have stored children *per Foo*. And not keyed by the parent's foo, but the child's foo. Does that make sense? I'll be working on this immediately, but if anyone can shorten my path to getting this straight I'd be very glad. I'm beginning to work out the use of a custom collection_class for this, but I haven't done all that much with metaclassing and the way forward isn't obvious (the SA instructions about this seem to assume the programmer is pretty experienced with custom subclassing etc.) --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?
Incidentally, I tried mocking this all up entirely outside of SA by creating a DictOfLists class that subclasses the basic 'dict'. That worked fine, returns lists, adds and removes as desired, handles everything as one would expect. So I don't think I'm fumbling with the basic mechanics of it. On Feb 15, 11:41 pm, Eric Ongerth [EMAIL PROTECTED] wrote: Ok, I tried subclassing MappedCollection and it seems like I did all right with my made-up appender, remover, and iterator functions. At least I fixed various errors and got this to at least function as the collection_class for the mapper shown above. But I can't figure out how to tell my DictOfLists to return a list instead of a single item. So there's a place where I'm trying to say: for child in some_bar.children[some_foo]: blah(child) etc. Sadly, while some_bar.children[some_foo] at least returns something, it returns a scalar Bar instance, not a list of Bars as I want it too. What's the next step? On Feb 15, 8:21 pm, Eric Ongerth [EMAIL PROTECTED] 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. On Feb 15, 8:13 pm, Eric Ongerth [EMAIL PROTECTED] wrote: If anyone out there has already implemented a custom DictOfLists collection class to map scalar keys to lists of values, I would be grateful for the opportunity to avoid reinventing the wheel. If not, I guess I'll start working on it. I've experimented successfully with attribute_mapped_collection and column_mapped_collection and they work just great. However, instead of mapping keys to single values, I need some of my mapper relations to map to a list of values. Here is more of the picture, for example. foos = Table('foos', metadata, Column('id', Integer, primary_key=True), Column('name', String(20))) bars = Table('bars', metadata, Column('id', Integer, primary_key=True), Column('foo_id', Integer, ForeignKey('foos.id')), Column('value', String(20)), Column('parent_id', Integer, ForeignKey('bars.id'))) class Foo(object): pass class Bar(object): pass mapper(Foo, foos) mapper(Bar, bars, properties={ 'foo':relation(Foo, uselist=False, backref='bars'), 'children':relation(Bar, backref=backref('parent', remote_side=[bars.c.id])) }) ... So we have a relation of 1 Foo : many Bars. And within the Bars we also have 'adjacency' (tree-like) relations between the various rows of the 'bars' table. A Bar's children are kept in the standard list-like collection class. But what I really need is a *dict* instead of a list. Ok, SA already takes care of that. But I actually need a list-like collection to appear as the value for each key in the dict. Specifically, I need each Bar to be able to have stored children *per Foo*. And not keyed by the parent's foo, but the child's foo. Does that make sense? I'll be working on this immediately, but if anyone can shorten my path to getting this straight I'd be very glad. I'm beginning to work out the use of a custom collection_class for this, but I haven't done all that much with metaclassing and the way forward isn't obvious (the SA instructions about this seem to assume the programmer is pretty experienced with custom subclassing etc.) --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com 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 -~--~~~~--~~--~--~---