> > Thanks a lot for the tips on how to approach this problem. That's
> > exactly what I needed.
>
> in 0.4 you'd get it off the impl (0.5 too, this is just uglier API):
Excellent! Here's what I came up with as an initial solution:
def poly_load(parent, collection, path):
def itersiblings(parent, path):
def iteritems(items, attr):
for item in items:
for child in getattr(item, attr):
yield child
items = [parent]
while path:
items = iteritems(items, path.pop(0))
return items
path = path.split(".")
assert len(path) % 2 == 0, "path must contain an even number of
elements"
mid = len(path) / 2
gparent = parent
for attr in path[:mid]:
gparent = getattr(gparent, attr)
session = sqlalchemy.orm.session.object_session(parent)
backref = getattr(type(parent), collection).property.backref.key
itemclass = getattr(type(parent),
collection).property.mapper.class_
qry = session.query(itemclass) \
.join([backref] + path[:mid]) \
.filter(type(gparent).table.c.id == gparent.id)
groups = defaultdict(list)
for item in qry:
groups[getattr(item, backref).id].append(item)
impl = getattr(type(parent), collection).impl
for sibling in itersiblings(gparent, path[mid:]):
if sibling.id in groups:
impl.set_committed_value(sibling._state, groups.get
(sibling.id))
Example usage:
# prepare for takeoff
order = session.get(Order, 123)
item = order.items[0] # triggers lazy load
# sit back and watch the fireworks!
poly_load(item, "attributes", "order.items")
# BOOM loaded all attributes of all items
poly_load(item, "tags", "order.items")
# BOOM loaded all tags of all items
poly_load(item.tags[0], "bars", "item.order.items.tags")
# BOOOM loaded all bars of all tags of all items
Some assumptions I was able to make that kept it simple:
- All mapped classes in my model have a 'table' attribute
- All entities in my model have an 'id' attribute, which is the
primary key.
- Relationships traversed by this loader are configured with the
necessary backrefs to make it work.
Initial tests seem to show a DRAMATIC performance improvement. Thanks
a lot for your help Mike.
Next up, roll this into a loader strategy so I can configure it on the
mapper and have it all happen automatically.
~ Daniel
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---