[sqlalchemy] Re: [Sqlalchemy-users] Typed Relations - Any Easier way to do Association Object?

2006-11-01 Thread Michael Bayer

(moving to google groups)

the idea of using an instrumented list subclass is that you *would*  
use the association object, and just have the list subclass handle  
the references to the association object for you, i.e.:

class MyList(list):
 def append(self, item):
 super(MyList, self).append(new ItemAssociation(item))
 def __getitem__(self, index):
 return super(MyList, self).__getitem__(index).item

..etc


On Nov 1, 2006, at 3:15 PM, Karl Guertin wrote:

 I'm working on a database where the relation between users and objects
 is defined by an association table that looks like:

 role_objects_table = Table(role_objects, metadata,
Column(objects_id, Integer,
   ForeignKey(objects.objects_id),
   primary_key=True),
Column(role,Role_Type),
Column(user_id, Integer,
   ForeignKey(tg_user.user_id),
   primary_key=True))

 Where Role_Type is an Enum class that translates roles onto Unicode 
 (1).

 And Objects is mapped like so:

 assign_mapper(session.context, Objects, objects_table, properties =  
 dict(
 #...
 responsibles = relation(User, secondary=role_objects_table,
 primaryjoin = and_(objects_table.c.objects_id ==
 role_objects_table.c.objects_id,
   role_objects_table.c.role == 'R')),
 approvers = relation(User, secondary=role_objects_table,
 primaryjoin = and_(objects_table.c.objects_id ==
 role_objects_table.c.objects_id,
   role_objects_table.c.role == 'A')),
#...
 )

 So basically the relationship between users and objects is typed by
 the role field. This is a textbook use case for the use of an
 association object, but using an association object is really
 annoying. I would really like to be able to treat each relation as a
 normal many to many relation and not have to create intermediate
 objects just to set one field to a constant value.

 In looking through the archives I found:

 You could go more nuts with [object properties] by having the list  
 be a
 subclass of list which properly does mutation operations too,  
 creates
 the association objects automatically, etc.

 Which seems to be what I'm looking to do. I'm assuming that the list
 referenced here is custom collection_class, but I don't see any
 obvious hooks into the secondary table and trying to manage the state
 of intermediate objects is more work than I'd like.

 In looking through the code, I noticed
 sqlalchemy.orm.attributes.AttributeExtension, which makes it pretty
 easy to hook into the event I'm interested in, but I'm having trouble
 finding a reference to the secondary table.

 Any guidance would be appreciated.

 -- 
 ---
 Using Tomcat but need to do more? Need to support web services,  
 security?
 Get stuff done quickly with pre-integrated technology to make your  
 job easier
 Download IBM WebSphere Application Server v.1.0.1 based on Apache  
 Geronimo
 http://sel.as-us.falkag.net/sel? 
 cmd=lnkkid=120709bid=263057dat=121642
 ___
 Sqlalchemy-users mailing list
 Sqlalchemy-users@lists.sourceforge.net
 https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: [Sqlalchemy-users] Typed Relations - Any Easier way to do Association Object?

2006-11-01 Thread Karl Guertin

On 11/1/06, Michael Bayer [EMAIL PROTECTED] wrote:
 (moving to google groups)

Eh, sorry cached email address.

 the idea of using an instrumented list subclass is that you *would*
 use the association object, and just have the list subclass handle
 the references to the association object for you, i.e.:

Simple enough

 class MyList(list):
  def append(self, item):
  super(MyList, self).append(new ItemAssociation(item))
  def __getitem__(self, index):
  return super(MyList, self).__getitem__(index).item

 ..etc

I'm not understanding what's happening in the append. I know item is
one side of my relation, but how to I get access to the other? Is the
InstrumentedList magic supposed to handle this somehow?

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: [Sqlalchemy-users] Typed Relations - Any Easier way to do Association Object?

2006-11-01 Thread Michael Bayer
OK, i was oversimplifying.  if you really want a total bi-directional  
many-to-many relationship where the association object is essentially  
invisible, you have to set up proxies in both directions.  The  
attached script illustrates an almost generic way of doing this  
which, after a few more iterations, could possibly become an  
extension to SA so that folks could re-use this approach without the  
ugliness.  It basically sets up a proxy list that translates the  
association instances in both directions to the underlying target  
object.   in this example, both sides of the association are many-to- 
many.  further property tricks can be used to make one side of it  
scalar instead



--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---
from sqlalchemy import *
m = BoundMetaData('sqlite://', echo=True)

objecttable = Table('objects', m,
Column('id', Integer, primary_key=True),
Column('data', String(30))
)

associationtable = Table('association', m,
Column('oid', Integer, ForeignKey('objects.id'), primary_key=True),
Column('iid', Integer, ForeignKey('items.id'), primary_key=True))

itemtable = Table('items', m, 
Column('id', Integer, primary_key=True),
Column('data', String(30))
)

m.create_all()

class Association(object):
association object
pass

class AssociationList(object):
generic proxying list which proxies list operations to a different 
list-holding attribute of the parent object, converting Association objects
to and from a target attribute on each Association object.
def __init__(self, parent, collectionname, attr):
create a new AssociationList.

parent - the parent object that contains this list
collectionname - the attribute name which stores the collection of Associations
attr - name of the attribute on the Association in which to get/set target values

self.parent = parent
self.collectionname = collectionname
self.attr = attr
def append(self, item):
a = Association()
setattr(a, self.attr, item)
getattr(self.parent, self.collectionname).append(a)
def __iter__(self):
return iter([getattr(x, self.attr) for x in getattr(self.parent, self.collectionname)])
def __repr__(self):
return repr([getattr(x, self.attr) for x in getattr(self.parent, self.collectionname)])
def __len__(self):
return len(getattr(self.parent, self.collectionname))
def __getitem__(self, index):
return getattr(getattr(self.parent, self.collectionname)[index], self.attr)
def __setitem__(self, index, value):
a = Association()
setattr(a, self.attr, value)
getattr(self.parent, self.collectionname)[index] = a

class AssocProp(object):
a property object that automatically sets up AssociationLists on a parent object.
def __init__(self, collectionname, attr):
create a new association property.

collectionname - the attribute name which stores the collection of Associations
attr - name of the attribute on the Association in which to get/set target values

self.collectionname = collectionname
self.attr = attr
def __get__(self, obj, owner):
if obj is None:
return self
storage_key = '_AssocProp_%s' % self.collectionname
try:
return getattr(obj, storage_key)
except AttributeError:
a = AssociationList(obj, self.collectionname, self.attr)
setattr(obj, storage_key, a)
return a

class MyObject(object):
items = AssocProp('associations', 'item')

class Item(object):
myobjs = AssocProp('associations', 'myobj')

mapper(MyObject, objecttable)
mapper(Item, itemtable)

mapper(Association, associationtable, properties={
'myobj':relation(MyObject, backref='associations'),
'item':relation(Item, backref='associations')
})

s = create_session()

o = MyObject()
o.items.append(Item())
o.items.append(Item())

i = Item()
i.myobjs.append(o)

s.save(o)
s.flush()
s.clear()

o = s.query(MyObject).get(o.id)
print o
print o.items
assert len(o.items) == 3
assert o in o.items[1].myobjs



On Nov 1, 2006, at 7:09 PM, Karl Guertin wrote:


 On 11/1/06, Michael Bayer [EMAIL PROTECTED] wrote:
 (moving to google groups)

 Eh, sorry cached email address.

 the idea of using an instrumented list subclass is that you *would*
 use the association object, and just have the list subclass handle
 the references to the association object for you, i.e.:

 Simple enough

 class MyList(list):