On Feb 27, 2011, at 6:45 PM, Hector Blanco wrote:

> A few days ago I asked what appears in the body of the message, a few
> lines below. To summarize:
> 
> Let's say I have a class "User" (yeah, to define "users" in my
> application) and each user can belong to one "UserGroup" (another
> class of my application). The User class would be something like:
> 
> 
> class User(declarativeBase):
>       """Represents a user"""
>       __tablename__ = "users"
> 
>       _id = Column("id", Integer, primary_key=True)
>       _firstName = Column("first_name", String(50))
>       _lastName = Column("last_name", String(50))
>       _userName = Column("user_name", String(50), unique=True, nullable=False)
>       _password = Column("password", String(64), nullable=False)
>       _userGroupId = Column("user_group_id", Integer, 
> ForeignKey("user_groups.id"))
> 
>       _userGroup = relationship("UserGroup", uselist=False)
> 
> 
>       id = synonym('_id', descriptor=property(getId, setId))
>       firstName = synonym('_firstName', descriptor=property(getFirstName,
>                                       setFirstName))
>       lastName = synonym('_lastName', descriptor=property(getLastName, 
> setLastName))
>       userName = synonym('_userName', descriptor=property(getUserName, 
> setUserName))
>       password = synonym('_password', descriptor=property(getPassword, 
> setPassword))
>       userGroupId = synonym('_userGroupId',
>                                       descriptor=property(getUserGroupId, 
> setUserGroupId))
>       userGroup = synonym('_userGroup', descriptor=property(getUserGroup,
>                                       setUserGroup))
> 
> I wanted to find a way to find which synonyms "pointed" to foreign
> keys and which ones pointed to relationships. Basically, having a
> couple of methods like the following:
>     def getRelationships(cls):
> that when invoked with getRelationships(User.User) would return a list
> with ["userGroup"] (withouth the "_" in front)
> and another:
>     def getForeignKeys(cls):
> that would return ["userGroupId"]
> 
> So far I've done this:
> 
> def getRelationships(cls):
>       retval = list()
>       mapper = sqlalchemy.orm.class_mapper(cls)
>       actualNameToSynonym = dict()
>       relationships = set()
> 
>       for prop in mapper.iterate_properties:
>               if isinstance(prop, sqlalchemy.orm.properties.SynonymProperty):
>                       actualNameToSynonym[prop.name] = prop.key
>                       # dictionary <_userName, userName, userGroup, 
> _userGroup>
> 
>               elif isinstance(prop, 
> sqlalchemy.orm.properties.RelationshipProperty):
>                       relationships.add(prop.key)
>                       #set with _userGroup, and rest of relationships
> 
>       for relationship in relationships:
>               retval.append(actualNameToSynonym[relationship])
> 
>       return retval
> 
> def getForeignKeys(cls):
>       retval = list()
>       mapper = sqlalchemy.orm.class_mapper(cls)
>       actualNameToSynonym = dict()
>       columnsWithForeignKeys = set()
> 
>       for prop in mapper.iterate_properties:
>               if isinstance(prop, sqlalchemy.orm.properties.SynonymProperty):
>                       actualNameToSynonym[prop.name] = prop.key
>                       # dictionary <_userName, userName, userGroup, 
> _userGroup>
> 
>               elif isinstance(prop, sqlalchemy.orm.properties.ColumnProperty):
>                       for column in prop.columns:
>                               if len(column.foreign_keys) > 0:
>                                       columnsWithForeignKeys.add(prop.key)
> 
>       for columnWithForeignKeys in columnsWithForeignKeys:
>               retval.append(actualNameToSynonym[columnWithForeignKeys])
>       return retval
> 
> Both are very similar: First they create a dictionary mapping the
> synonym's key with the "real" name (<_userGroup, userGroup>) and store
> the "relationships" or the columns that have a "foreign key" in a set
> (for the method that tries to get relationships, that set would be
> set("_userGroup") and for the one that tries to get foreign keys,
> set("_userGroupId")) . In a second "for" loop they match that
> "underscored" name with the name of the synonym to return a list with
> the names of the synonyms, and not the actual columns (basically, to
> transform "_userGroupId" to "userGroupId")
> 
> They seem to work, at least with my not-complicated-at-all classes,
> but I'd like to know what do you guys think of my approach. Is it
> good? Can it break something? Is there a better way?

No thats a pretty OK way , there's an argument called "resolve_synonyms" to 
get_property() in 0.6 but that's gone away in 0.7 anyway.   There aren't too 
many choices for types of *Property.   Perhaps if you wanted to handle 
CompositeProperty, though you wouldn't need to do so in 0.7 since composite 
doesn't "replace" the column props in 0.7.

Of course using all those descriptors for every attribute is a pretty 
java-esque way of going about things but that's a different issue.



> 
> Thank you!
> 
> 
> 
> 2011/2/18 Hector Blanco <white.li...@gmail.com>:
>> I'll give it a try!!
>> 
>> Thank you!
>> 
>> 2011/2/18 Michael Bayer <mike...@zzzcomputing.com>:
>>> 
>>> On Feb 17, 2011, at 6:37 PM, Hector Blanco wrote:
>>> 
>>>> Hello everyone!
>>>> 
>>>> Let's say I have a class defined like this:
>>>> 
>>>> class User(declarativeBase):
>>>>       """Represents a user"""
>>>>       __tablename__ = "users"
>>>> 
>>>>       _id = Column("id", Integer, primary_key=True)
>>>>       _phone = Column("phone", String(16))
>>>>       _userName = Column("user_name", String(50), unique=True, 
>>>> nullable=False)
>>>>       _password = Column("password", String(64), nullable=False)
>>>> 
>>>>       _userGroupId = Column("user_group_id", Integer, 
>>>> ForeignKey("user_groups.id"))
>>>>       _userGroup = relationship("UserGroup", uselist=False)
>>>> 
>>>>       def setId(self, id):
>>>>               """Set id"""
>>>>               self._id = int(id)
>>>> 
>>>>       def getId(self):
>>>>               """Get id"""
>>>>               return self._id
>>>> 
>>>>       def setUserGroupById(self, userGroupId):
>>>>               userGroupId = int(userGroupId)
>>>>               if userGroupId != self.userGroupId:
>>>>                       self.userGroup = 
>>>> UserGroupManager.getById(userGroupId)
>>>> 
>>>>       def setUserGroup(self, userGroup):
>>>>               """Set user group"""
>>>>               if isinstance(userGroup, UserGroup):
>>>>                       self._userGroup = userGroup
>>>>               else:
>>>>                       raise TypeError("Trying to set a " + 
>>>> str(type(userGroup)) + " as user group")
>>>> 
>>>>       def getUserGroup(self):
>>>>               """Get user"""
>>>>               return self._userGroup
>>>> 
>>>>       #More getters/setters
>>>> 
>>>>       id = sqlalchemy.orm.synonym('_id', descriptor=property(getId, setId))
>>>>       phone = sqlalchemy.orm.synonym('_phone',
>>>> descriptor=property(getPhone, setPhone))
>>>>       userName = sqlalchemy.orm.synonym('_userName',
>>>> descriptor=property(getUserName, setUserName))
>>>>       password = sqlalchemy.orm.synonym('_password',
>>>> descriptor=property(getPassword, setPassword))
>>>>       userGroupId = sqlalchemy.orm.synonym('_userGroupId',
>>>> descriptor=property(getUserGroup, setUserGroup))
>>>>       userGroup = sqlalchemy.orm.synonym('_userGroup',
>>>> descriptor=property(getUserGroup, setUserGroup))
>>>> 
>>>> I have created an utility that, given an instance gives me the names
>>>> of the synonyms in said instance.
>>>> 
>>>> def getProperties(instance):
>>>>       properties = list()
>>>>       mapper = sqlalchemy.orm.object_mapper(instance)
>>>>       for prop in mapper.iterate_properties:
>>>>               if isinstance(prop, 
>>>> sqlalchemy.orm.properties.SynonymProperty):
>>>>                       properties.append(prop.key)
>>>>       return properties
>>>> 
>>>> That would give me ["id", "phone", "userName", "password",
>>>> "userGroupId", "userGroup"], so I can more or less generically go
>>>> through all said values and execute things like
>>>> 
>>>> for attribute in getProperties(instanceOfUser):
>>>>     value = getattr(instanceOfUser, attribute)
>>>> 
>>>> Is there any way of knowing that said "value"s are ForeignKeys or
>>>> relationships? For instance, I'd like to know that the attribute "id"
>>>> is a regular (well... kind of regular... it's a Primary key, but it's
>>>> not going to point to anything in another table) numeric attribute,
>>>> but "userGroupId" is a foreign key and "userGroup" is a Relationship.
>>>> I've been sneaking in the vars, __dict__, dir of the values returned
>>>> by getattr, but I haven't been able to find anything suitable.
>>> 
>>> 
>>> you just have to poke around and use isinstance() on the MapperProperty 
>>> objects, and/or check for known attributes.    The choices are 
>>> ColumnProperty, RelationshipProperty, SynonymProperty, etc.
>>> 
>>> synonyms are also superceded in 0.7.  they're not very useful compared to 
>>> hybrids.
>>> 
>>> 
>>> 
>>> 
>>> --
>>> 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.
>>> 
>>> 
>> 
> 
> -- 
> 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.
> 

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

Reply via email to