Hello everyone. I have a kind of "virtual" class that I want to use as base class for all the elements that are going to be stored in the database.
Initially I had: ---------- BaseClass.py ---------- class BaseClass(object): _id = Column("id", Integer, primary_key=True, key="id") 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 @declared_attr def id(cls): return synonym('_id', descriptor=property(cls.getId, cls.setId)) ------------------------------ And that was working really fine. But now I want to add a relationship N:M from this BaseClass to UserGroup, to control the visibility of the objects in the System. I want that only certain "UserGroups" can see certain elements. I.e.: Let's say I have another class "Store" and I want only the users belonging to certain userGroup(s) to be able to see some of the "Store" instances (i.e.: only usergroups with ids 5 or 6 will be able to see stores id== 3,4,5... only usergroups 5, 7 and 8 will be able to access stores 5, 8) . To accomplish that, I would create an N:M relationship between the "Store" and "UserGroup" classes: class Store(BaseClass.BaseClass, Database.Base): __tablename__ = "stores" _name = Column("name", String(50)) _number = Column("number", Integer) _userGroups = relationship("UserGroup", secondary=user_group_store, primaryjoin=lambda: Store.id == user_group_store.c.store_id, secondaryjoin=lambda: UserGroup.UserGroup.id == user_group_store.c.user_group_id, collection_class=set ) By setting this relationship, (and, of course, with the intermediate table "user_group_store" which relates UserGroups with Stores) I can easily "filter" the stores that a UserGroup can see using: query = session.query(Store.Store).join('userGroups') .filter(UserGroup.UserGroup.id == int(userGroupId)) .all() But now I want to do that not only with the "Store" class but with every element in my system, so I can filter every class stored in the database by "UserGroup" (something like it says in http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#mixing-in-relationships, but N:M and with a different intermediate table per class to relate to "UserGroup") I tried to move that relationship to the BaseClass detailed above (in a similar way to the id): --------------------------- BaseClass.py -------------------- from myclasses.database import Tables #Tables is the module where the intermediate tables are defined. # If I want to be able to relate UserGroup with Store, in that "Tables" modules # I will create a table (in Tables.py) like: # intermediate_allowed_user_groups_to_stores = Table( # "intermediate_allowed_user_groups_to_stores", # Base.metadata, # Column("id", Integer, primary_key=True), # Column("element_id", Integer, ForeignKey("stores.id"), key="elementId"), # Column("user_group_id", # Integer, ForeignKey("user_groups.id"), # key="userGroupId") #) 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 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 sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.