On Mar 23, 2011, at 5:47 PM, Hector Blanco wrote:

> Hello everyone.
> 
> 
> class BaseClass(object):
>       sqlRelationships_accelerator = None
>       internalAttrs_accelerator = None
>       properties_accelerator = None
> 
>       _id = Column("id", Integer, primary_key=True, key="id")
> 
>       @classmethod
>       def intermediate_allowed_user_groups_to_this(cls):
>               retval = None
>               try:
>                       mapper = class_mapper(cls)
>               except ormExc.UnmappedClassError:
>                       mapper = None
> 
>               if mapper and (mapper.local_table is not None):
>                       try:
>                               retval = getattr(Tables,
>                                       
> ("intermediate_allowed_user_groups_to_%s"
>                                       % mapper.local_table.name))
>                       except KeyError:
>                               return None
>               return retval
> 
>       @declared_attr
>       def _allowedUserGroups(cls):
>               if cls:
>                       intermediateTable = 
> cls.intermediate_allowed_user_groups_to_this()
>                       if intermediateTable is not None:
>                               return relationship("UserGroup",
>                                       secondary="intermediateTable",
>                                       primaryjoin="%s._id == 
> intermediateTable.elementId" % cls.__name__,
>                                       secondaryjoin="UserGroup._id == 
> intermediateTable.userGroupId",
>                                       collection_class=set
>                               )
>               return None

there's an enormous amount of complexity here for me to gather, its not 
runnable either, which basically means I'm going to skip it.   In particular 
the whole digging into mappers and finding tables seems unnecessary, just 
create the m2m table for the relationship as needed.

For the general case of "everyone has a many-to-many to X", a short example is 
attached.  I hope to blog more about this kind of thing as an updated approach 
to that discussed in the old Polymorphic Associations post.







> 
>       def __hash__(self):
>               return int(self.id)
> 
>       def setId(self, id):
>               """Set id"""
>               self._id = int(id)
> 
>       def getId(self):
>               """Get id"""
>               return self._id
> 
>       def setAllowedUserGroups(self, allowedUserGroups):
>               self._allowedUserGroups = set(allowedUserGroups)
> 
>       def getAllowedUserGroups(self):
>               return self._allowedUserGroups
> 
>       @declared_attr
>       def allowedUserGroups(cls):
>               return synonym('_allowedUserGroups',
>                       descriptor=property(cls.getAllowedUserGroups,
>                                                   cls.setAllowedUserGroups))
> ----------------------------------------
> 
> The "intermediate_allowed_user_groups_to_this" classmethod tries to
> grab the intermediate table from the Tables module based on the name
> of the table where the actual instances of the class (descending from
> BaseClass) are going to be stored. Going back to the Store class, the
> __tablename__ is "stores". The
> intermediate_allowed_user_groups_to_this method will try to grab a
> table called "intermediate_allowed_user_groups_to_stores" (because
> that is the intermediate table that would link UserGroups and Stores)
> 
> * What I wanted to achieve:
> To filter by userGroup, I just wanted to need adding an intermediate
> table to the Tables module relating the UserGroup with the class to
> filter (as I explained, if I wanted to filter "Store", which is stored
> in the table
> "stores", I just need to create a table called
> "intermediate_allowed_user_groups_to_stores", or if I wanted to filter
> "Foo", stored in the "foos" table, I would just need to create
> "intermediate_allowed_user_groups_to_foos" and the baseclass, with its
> declared_attribute relationship, helped by the
> "intermediate_allowed_user_groups_to_this" would take care of the
> rest.
> 
> What I got:
> 
> Traceback (most recent call last):
>  File "/home/ae/ev-cms/server/src/server/app.py", line 30, in __init__
>    SetupDB.setupDB()
>  File "/home/ae/ev-cms/backlib/database/SetupDB.py", line 26, in setupDB
>    populateWithSamples()
>  File "/home/ae/ev-cms/backlib/database/SetupDB.py", line 86, in
>            populateWithSamples
>    samples = Store.Store.getSamples()
>  File "/home/ae/ev-cms/backlib/store/Store.py", line 379, in getSamples
>    store = cls()
>  File "<string>", line 4, in __init__
>  File 
> "/home/ae/.buildout/eggs/SQLAlchemy-0.6.6-py2.6.egg/sqlalchemy/orm/state.py",
> line 111, in initialize_instance
>    return manager.events.original_init(*mixed[1:], **kwargs)
>  File "/home/ae/ev-cms/backlib/store/Store.py", line 73, in __init__
>    self.allowedUserGroups = set()
>  File 
> "/home/ae/.buildout/eggs/SQLAlchemy-0.6.6-py2.6.egg/sqlalchemy/orm/attributes.py",
> line 210, in __set__
>    return descriptor.__set__(instance, value)
>  File "/home/ae/ev-cms/backlib/database/BaseClass.py", line 80, in
> setAllowedUserGroups
>    self._allowedUserGroups = set(allowedUserGroups)
> AttributeError: can't set attribute
> 
> 
> ... it didn't even get pass the Store.Store constructor... :-D
> 
> class Store(BaseClass.BaseClass, declarative_base)
>       def __init__(self):
>               super(Store, self).__init__()
>               self.name = ""
>               self.allowedUserGroups = set() # Crack!
> 
> If I remove the line self.allowedUserGroups = set() from the
> constructor, I get this:
>  File "/home/ae/ev-cms/backlib/database/BaseClass.py", line 86, in
> addAllowedUserGroup
>    self.allowedUserGroups.add(userGroup)
> AttributeError: 'RelationshipProperty' object has no attribute 'add'
> 
> I guess is not that easy... :-)
> 
> I'm sure it's doable... but I don't know how... Any hint will be appreciated.
> 
> As usual, thank you in advance
> 
> -- 
> 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.
> 

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr

class Base(object):
    id = Column('id', Integer, primary_key=True)

Base = declarative_base(cls=Base)

class HasRelationToGroup(object):
    @declared_attr
    def groups(cls):
        secondary = Table('%s_groups' % cls.__tablename__,
            cls.metadata,
            Column('parent_id', Integer, ForeignKey('%s.id' % cls.__tablename__), primary_key=True),
            Column('group_id', Integer, ForeignKey('group.id'), primary_key=True),
        )
        return relationship(
            UserGroup, secondary=secondary,collection_class=set
            # if you needed primaryjoin/secondaryjoin here, which
            # your example shouldn't, using lambdas or strings helps 
            # with that auto-gen "Base.id"
            # column above being evaluated at the right time
        )

class UserGroup(Base):
    __tablename__ = 'group'

    name = Column(String)

class User(HasRelationToGroup, Base):
    __tablename__ = 'user'

    name = Column(String)

e = create_engine('sqlite://', echo=True)
Base.metadata.create_all(e)

s = Session(e)

g1, g2 = UserGroup(name='g1'), UserGroup(name='g2')
s.add_all([
    User(name='u1', groups=set([g1, g2])),
    User(name='u2', groups=set([g2])),
])

s.commit()

print s.query(User).join(User.groups).filter(UserGroup.name=='g2').all()
-- 
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.

Reply via email to