Google Groups

Define a custom collection


Luca Wehrstedt Jan 14, 2013 1:17 AM
Posted in group: sqlalchemy
Hello everyone,

I'm posting here because I don't know if the issues I'm having are bugs or just improper use of the library.

I'd like to define a custom collection class since I'm not completely satisfied by the default ones. In particular I'd like to subclass MappedCollection and make it provide more consistency. That is, if on a `parent` object I have a `children` attribute which is an instance of my new collection class and contains objects of the `Child` class indexed by their `column` attribute, I want:
  • `parent['new_key'] = existing_child` to do `del parent['old_key']` (if the child was already in the collection) and `existing_child.column = 'new_key'` (and also remove the object previously associated with 'new_key', if any, from the collection, as MappedCollection already does [1])
  • `existing_child.column = 'new_key'` to have the same effects as `parent['new_key'] = existing_child`, described above.
[1] I forgot to mention that I assume there to be a UniqueConstraint on the value of `Child.column`

My plan to do all of this was:
  • to pass the name of the `column` attribute as a parameter to the constructor of the class
  • to have the class figure out by itself which object/classes/relationships it was bound to, using the collection adapter
  • to have the collection listen on 'set' events of the `column` property of the `Child` class
  • do all the "magic" inside the event listener and the __setitem__ method
Additionally, I wanted to override the converter to make it accept any sequence (list, set, etc.) of Child objects, since the collection knows how to extract their keys and make it become a dictionary.

While trying to do it I faced the following issues:
  • I tried to define a method "def link(self, adapter):" with the "@collection.link" decorator but it didn't work (it wasn't called by SA). By looking at the code I guessed that a workaround would be to call the method `_sa_on_link` and, indeed, it worked. What's the proper way to use the "collection.link" decorator?
  • I was able to add a listener for 'set' events but not to remove it. A comment in the code said that this feature is not implemented and gave suggestions on how to do it. No big issue, since the collection is almost never unlinked and thus it's hardly needed to remove the listener, yet it's an undocumented behavior.
  • I tried to define a method "def convert(self, collection):" with the "@collection.converter" decorator but it didn't work. Even renaming it to "_sa_converter" didn't help. How can I override the converter of MappedCollection (that I'm subclassing)?
Thanks for any help you can provide,

Luca