Created
December 13, 2016 20:05
-
-
Save onecrayon/646da61accf54674d4f5098376a2c5df to your computer and use it in GitHub Desktop.
Custom MappedCollection example for SQLAlchemy returning a dict of lists
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"> | |
] | |
} | |
""" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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