Custom Identity Model

4 views
Skip to first unread message

Randall

unread,
Jan 27, 2006, 7:35:36 PM1/27/06
to TurboGears
First, thanks to Jeff Watkins and all those who contributed to
Identity. I'm looking forward to using it in my applications.

When beginning to use Identity, I discovered I would need some
additional attributes for TG_User. I did some searching to find out
how to create my own User class and got things working. The classes
defined in soprovider.py inherit from InheritableSQLObject instead of
SQLObject. I'm guessing this is to encourage subclassing these, but I
think subclassing would work better if the soprovider.py classes just
inherited from SQLObject.

As it is currently written, subclassing will create additional tables
that contain the "extra" attributes, so each class (User, Group,
Permission) requires two tables instead of one. It will work, but it
is ugly. Also, in my experience, setting properties on the subclass
(e.g. _set_password) does not work. My solution was to create User,
Group and Permission classes that don't inherit from the soprovider
classes. The downside to this is that I don't inherit anything and I
would bet the jsonify stuff doesn't work because my classes don't
inherit from TG_*.

I propose that the TG_User, TG_Group and TG_Permission inherit from
SQLObject. This way, only one table will be created for a subclass and
setting properties should work. Also, everything else in the module
(jsonify_group) should keep working.

OTri

unread,
Feb 10, 2006, 4:20:21 AM2/10/06
to TurboGears
I'm struggling with this Identify stuff just now. I would like to
inherit TG_User but cannot think of a good way to untie myself from
some of the restrictions you mention. Unfortunately I don't quite
understand all of how TG works to safely make a decision on how to
change any of this. Could anyone explain how to safely extend TG_User
with custom attributes?

Ronald Jaramillo

unread,
Feb 10, 2006, 5:06:25 AM2/10/06
to turbo...@googlegroups.com
Hi,
This fx. works for me:

class Person(TG_User):
projects = MultipleJoin("Project",joinColumn='owner_id')
workgroups = RelatedJoin("Workgroup")
myworkgroups = MultipleJoin("Workgroup",joinColumn='owner_id')

class Workgroup(TG_Group):
creator = ForeignKey("Person")

class Project(SQLObject):
name = StringCol(length=250)
created = DateTimeCol(default=datetime.now)
owner = ForeignKey("Person")


Just remember to change your config.py file accordantly:

identity.soprovider.model.user='kronos.model.Person'
identity.soprovider.model.group='kronos.model.Workgroup'

Cheers
Ronald

ps. does anybody knows why config.py and devcfg.py+prodcfg.py aren't
on the same directory?

________________________________
Ronald Jaramillo
mail: ronald AT checkandshare DOT com
blog: http://www.checkandshare.com/blog

Kevin Dangoor

unread,
Feb 10, 2006, 6:32:04 AM2/10/06
to turbo...@googlegroups.com
On 2/10/06, Ronald Jaramillo <ron...@checkandshare.com> wrote:
> ps. does anybody knows why config.py and devcfg.py+prodcfg.py aren't
> on the same directory?

They serve different purposes... config.py is application
configuration that doesn't depend on where it's being deployed. As
such, it gets bundled up in your egg so that it can be dropped in on a
target system. devcfg.py+prodcfg.py are the deployment-specific
configuration files.

Kevin

Hootbah

unread,
Feb 10, 2006, 8:07:50 AM2/10/06
to TurboGears
I'm having a few porblems also extending the TG_User class.

I have extended TG_User, TG_Group and TG_Permission as explained above
and all seems to workish.

However when I add the lines to my config.py:

import myproj.model
identity.soprovider.model.user=myproj.model.MyUser
identity.soprovider.model.group=myproj.model.MyGroup
identity.soprovider.model.permission=myproj.model.MyPermission

I get the error:
TurboGears-0.9a0dev_r708-py2.4.egg/turbogears/database.py", line 146,
in set_hub
raise KeyError, "No database configuration found!"

If I remove the above lines from config.py, things appear to work and
through my code I can create MyUser and MyGroup objects and use the
identity framework.

Is this a bug or am I missing some other configuration options
somewhere.

Thanks,

Hootbah.

Alberto

unread,
Feb 10, 2006, 8:16:23 AM2/10/06
to TurboGears
Randall wrote:

> As it is currently written, subclassing will create additional tables
> that contain the "extra" attributes, so each class (User, Group,
> Permission) requires two tables instead of one. It will work, but it
> is ugly. Also, in my experience, setting properties on the subclass
> (e.g. _set_password) does not work. My solution was to create User,
> Group and Permission classes that don't inherit from the soprovider
> classes. The downside to this is that I don't inherit anything and I
> would bet the jsonify stuff doesn't work because my classes don't
> inherit from TG_*.
>

+1, I also thing the two tables are ugly (very ugly IMO) and are a pain
to integrate with other ways to access the database (via psql, for
example, I mean, how could I explain my client how they should
hand-tweak the user tables using a plain ol' SQL UPDATE?? ).

> I propose that the TG_User, TG_Group and TG_Permission inherit from
> SQLObject. This way, only one table will be created for a subclass and
> setting properties should work. Also, everything else in the module
> (jsonify_group) should keep working.

I'm not very sure about this, If I remember correctly, when I was
playing for the first time with SQLObject that subclassing SQLObject
instances did not work as expected, I don't remeber exactly in what
ways, though...

RFC:

What I propose is a simplification of the tables, that is, the bare
minimum the identity framework needs to work so we can concentrate on
keeping that stable so it doesn't break on future releases.

That is:

class TG_User(InheritableSQLObject):
# Inheritable just in case someone still wants to use the current
inheritance mechanics
# userId is the pseudo "primary key" used by the rest of the
framework
userId= UnicodeCol( length=16, alternateID=True )
# password just needs to be there to properly validate
password= UnicodeCol( length=40 )
# we need relations :)
groups= RelatedJoin( "TG_Group", intermediateTable="tg_user_group",
joinColumn="user_id", otherColumn="group_id" )

class TG_Group(InheritableSQLObject):
# ditto
groupId= UnicodeCol( length=16, alternateID=True )
# ditto
users= RelatedJoin( "TG_User", intermediateTable="tg_user_group",
joinColumn="group_id", otherColumn="user_id" )
#ditto
permissions= RelatedJoin( "TG_Permission", joinColumn="group_id",
intermediateTable="tg_group_permission",
otherColumn="permission_id" )

class TG_Permission(inheritableSQLObject):
#ditto
permissionId= UnicodeCol( length=16, alternateID=True )
# ditto
groups= RelatedJoin( "TG_Group",
intermediateTable="tg_group_permission",
joinColumn="permission_id",
otherColumn="group_id" )

The rest of the current columns, IMO, are application specific... and
shouldn't be there. I personally don't care when a group was created
neither I use a displayName: I have a firstName and lastName and
__unicode__ for... displaying.

What i'm suggesting with this is, given that sqlobjects are a pain to
subclass, we should not even subclass them. Just create our app
specific models with the bare attributes the identity framework needs
and add our application specific stuff as we might need. We could even
make a quickstart template that generates a custom id_model at the
newly created project so users can easily customize further from there.

jsonify_* should work as expected (but a small tweak has to be done to
the generic dispatcher's conditions to use the custom classes defined
at config.py, probably this is the ONLY change needed, but haven't
tested to be sure).

I'm willing to volunteer to apply the needed changes if there is a
consensus.

Opinions?

Alberto

P.S. I know these are not identity framework's inherent limitations,
just the way InheritableSQLObject happens to work. And I really
appreciate the work Jeff has done on this, but that doesn't mean it
can't be improved.

Alberto

unread,
Feb 10, 2006, 8:21:46 AM2/10/06
to TurboGears
The config syntax has changed:

import myproj.model
identity.soprovider.model.user=myproj.model.MyUser
identity.soprovider.model.group=myproj.model.MyGroup
identity.soprovider.model.permission=myproj.model.MyPermission

should be:

identity.soprovider.model.user="myproj.model.MyUser"
identity.soprovider.model.group="myproj.model.MyGroup"
identity.soprovider.model.permission="myproj.model.MyPermission"

See http://trac.turbogears.org/turbogears/ticket/461

Alberto

Hootbah

unread,
Feb 10, 2006, 8:31:26 AM2/10/06
to TurboGears
Thanks for your help. That fixed the problem.


Hootbah.

OTri

unread,
Feb 11, 2006, 12:57:45 AM2/11/06
to TurboGears
Awesome.. yeah, I ran across that ticket number too. (Thank you
google!)

Now I have all that working.

Reply all
Reply to author
Forward
0 new messages