attached is an approach that uses just the tiniest amount of awareness of how a mapper works, to do the whole optimized loading scenario ahead of time, and you get an object with your two distinct "pro" and "con" relationships, no list decoration or anything needed. the appropriateness of this approach comes from the fact that your optimization case is a load-time optimization, therefore put the complexity at load time (which is easier to deal with since it doesnt have to be concerned with collection mutability).
--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
from sqlalchemy import * class SomeClass(object):pass class Position(object): def __init__(self, data, type): self.data = data self.type = type metadata = BoundMetaData('sqlite://', echo=True) t1 = Table("t1", metadata, Column('id', Integer, primary_key=True), Column('data', String(30))) t2 = Table('t2', metadata, Column('id', Integer, primary_key=True), Column('parent_id', Integer, ForeignKey('t1.id')), Column('data', String(30)), Column('type', String(20)) ) metadata.create_all() class MyExt(MapperExtension): def populate_instance(self, mapper, context, row, instance, identitykey, isnew): # tell the mapper to populate the instance like it always does mapper.populate_instance(context, instance, row, identitykey, isnew) # get the "row decorator" that will translate the eager loaded row to something # based off the columns in "t2" decorator = context.attributes[id(mapper.props['_positions'].strategy)] row = decorator(row) # determine pro or con - create instance and append to either collection if row[t2.c.type] == 'pro': instance.pro.append(class_mapper(Position)._instance(context, row, None)) elif row[t2.c.type] == 'con': instance.con.append(class_mapper(Position)._instance(context, row, None)) # alternatively! get the instance that was just appended to _positions # if _positions[-1].type == 'pro': # instance.pro.append(_positions[-1]) # ...etc # tell the calling mapper "populate_instance" is taken care of return None mapper(SomeClass, t1, extension=MyExt(), properties={ '_positions':relation(Position, lazy=False, viewonly=True), 'pro':relation(Position, lazy=None, primaryjoin=and_(t1.c.id==t2.c.parent_id,t2.c.type=='pro')), 'con':relation(Position, lazy=None, primaryjoin=and_(t1.c.id==t2.c.parent_id,t2.c.type=='con')) }) mapper(Position, t2) sess = create_session() sc =SomeClass() sc.pro.append(Position("tastes great", "pro")) sc.pro.append(Position("less filling", "pro")) sc.con.append(Position("beer sucks", "con")) sess.save(sc) sess.flush() sess.clear() sc = sess.query(SomeClass).get(sc.id) assert [x.data for x in sc.pro] == ["tastes great", "less filling"] assert [x.data for x in sc.con] == ["beer sucks"]
On Apr 16, 2007, at 8:00 PM, jason kirtland wrote: > > Michael wrote: >> On Apr 12, 2007, at 2:03 PM, jason kirtland wrote: >>> [...] >>> This does work, but because relation updates are happening >>> outside of the InstrumentedList (i.e. not on 'analysis' >>> directly), I'm losing the events that would normally be >>> triggered. I don't think I can manually manage them either, as >>> they're private __methods on InstrumentedList. >> >> some ideas which im not sure if theyd work, one is to not use >> "collection_class" and to go with an approach that is more like >> the AssociationProxy - i.e. "pro" and "con" have special >> collections on them which proxy to the utlimate "associations" >> colleciton, but on top of the InstrumentedList instead of >> underneath it the way collection_class does. > > I've got a new implementation that uses this approach and it does > work- but it is even more complex. If the InstrumentedCollection > refactor (#213) allows implementors to choose when to fire add/del > events I think this sort of pattern can be made pretty simple. > > On that front, I think it would be super useful if future > InstrumentedCollection classes have access to their relation() > arguments- e.g. a DRY ordered collection that keys off the > relation's order_by. A chance to error out at definition time > would be useful too. > > -jek > > > --~--~---------~--~----~------------~-------~--~----~ > 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 sqlalchemy- > [EMAIL PROTECTED] > For more options, visit this group at http://groups.google.com/ > group/sqlalchemy?hl=en > -~----------~----~----~----~------~----~------~--~--- >