Skip to content

Instantly share code, notes, and snippets.

@onecrayon
Created December 13, 2016 20:05
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onecrayon/646da61accf54674d4f5098376a2c5df to your computer and use it in GitHub Desktop.
Save onecrayon/646da61accf54674d4f5098376a2c5df to your computer and use it in GitHub Desktop.
Custom MappedCollection example for SQLAlchemy returning a dict of lists
from sqlalchemy import Model, Column, Integer, ForeignKey, String, Text
from orm_helpers import KeyedListCollection
class ItemAttribute(Model):
__tablename__ = 'item_attributes'
id = Column(Integer, primary_key=True, autoincrement=True)
item_id = Column(Integer, ForeignKey('items.id'))
attribute = Column(String(255))
value = Column(Text)
class Item(Model):
__tablename__ = 'items'
id = Column(Integer, primary_key=True, autoincrement=True)
attributes = db.relationship(ItemAttribute,
collection_class=lambda: KeyedListCollection('attribute'),
cascade='all, delete-orphan')
"""This relationship allows you to access your attributes as a list of ItemAttribute objects,
keyed off their `attribute` value. So `item.attributes` might return something like this:
{
'title': [ <ItemAttribute attribute="title" value="Example"> ]
'features': [
<ItemAttribute attribute="features" value="Hello">,
<ItemAttribute attribute="features" value="World">
]
}
"""
import operator
from sqlalchemy.orm.collections import MappedCollection, collection
class KeyedListCollection(MappedCollection):
"""This transforms a collection of attribute values into a dict of lists.
This is useful when representing an EAV table, for instance, because
any given attribute can have multiple values, but it is typically
most useful to access them by attribute name.
"""
def __init__(self, key):
super(KeyedListCollection, self).__init__(operator.attrgetter(key))
@collection.internally_instrumented
def __setitem__(self, key, value, _sa_initiator=None):
if not super(KeyedListCollection, self).get(key):
super(KeyedListCollection, self).__setitem__(key, [], _sa_initiator)
super(KeyedListCollection, self).__getitem__(key).append(value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment