Homogenization of User and UserProfile

144 views
Skip to first unread message

Michael A. Ryan

unread,
Mar 15, 2011, 4:49:05 PM3/15/11
to django-d...@googlegroups.com
Hello developers,

I've been using Django for a couple of months now on a new project and I've come across something which I think might be improved upon. It deals with the nature of UserProfile, which I think is a very handy tool overall.

The thing I'm not totally satisfied with is the way that UserProfile and User are totally separate objects once you have them at the python level. An example of an area where this separation might be an issue is making a JSON web service that needs to send a full User object to a client. In a typical client app, your User object is most likely one robust object which you have to express in Django as both User and UserProfile. So when you go to pipe this information through a tool like Django-Piston, you have to do a bit of slicing and dicing in your handler code to get both objects through in the same request, or manually create a nice neat object for Piston to deliver to the client in a way the client will be able to consume without having to worry about matchmaking Users and Profile.user_id fields.

Now, I am really not even advanced in Python, and I've only been using Django for a couple of months, but it seems to me like having a convenience method similar to get_profile() that automatically enumerates through your profile object and produces a flattened version of your client friendly user object might be a very useful thing to have.

Maybe there is already an easy and kosher way to do this in Python that I am unaware of, regardless, it just seems like something that would be handy to have for people who deal primarily with using Django to serve non-web clients.

I don't have a good sense of if this is something that is appropriate for Django Auth or should just be a property of my custom profile object, but I thought I might throw it out there for consideration.

Thanks for your time,

Michael

Ivan Sagalaev

unread,
Mar 17, 2011, 4:03:28 AM3/17/11
to django-d...@googlegroups.com
On 03/15/2011 01:49 PM, Michael A. Ryan wrote:
> In a typical client app, your User object is most
> likely one robust object which you have to express in Django as both
> User and UserProfile.

It's kind of hard to talk about "typical" Django app because there are
so many different of them :-). However what's for sure is that
significant share of Django projects consist of many apps. And those app
may store their own profile information related to users. For example
imagine some community site with a forum (an app), news comment system
(another app) and anti-spam plugin (yet another app). A forum keeps
track of users' achievements, comment system knows users' OpenID and
anti-spam have a notion of users' karma. All those things are parts of a
user profile.

If you think in these terms then the whole notion of a single default
UserProfile becomes moot. Yes, it exists and does its job for simple
situations but it's not a good ground for extensibility.

> So when you go to pipe this information through
> a tool like Django-Piston, you have to do a bit of slicing and dicing
> in your handler code

Actually, you will have to do it anyway. Your API shouldn't just expose
your internal model structure because it strongly couples interface to
implementation. In any non-trivial systems APIs cannot be auto-generated.

Alexander Schepanovski

unread,
Mar 18, 2011, 8:09:03 AM3/18/11
to Django developers
I think using subclass of User model for your fields has the same
flexibility as separate profile model (since you can have only one).
contrib.auth can be fairly simply adjusted to use custom User model
from settings instead of always using its own User.
In that sense I am totally for homogenization because it will make
code cleaner and eliminate unnecessary sql request not because of
serialization.

Such code is really an eyesore:
first_name = user.first_name
middle_name = user.get_profile().middle_name
last_name = user.last_name

> It's kind of hard to talk about "typical" Django app because there are
> so many different of them :-). However what's for sure is that
> significant share of Django projects consist of many apps. And those app
> may store their own profile information related to users. For example
> imagine some community site with a forum (an app), news comment system
> (another app) and anti-spam plugin (yet another app). A forum keeps
> track of users' achievements, comment system knows users' OpenID and
> anti-spam have a notion of users' karma. All those things are parts of a
> user profile.

What do you do in such situation? Create a profile class containing
all required fields? And then if you update some app you need to
update your composite UserProfile model?

One solution could be making each app provide its profile model,
abstract model and mixin. So that you can construct whatever you want
from this pieces.

Carl Meyer

unread,
Mar 18, 2011, 10:22:51 AM3/18/11
to django-d...@googlegroups.com

On 03/18/2011 08:09 AM, Alexander Schepanovski wrote:
> I think using subclass of User model for your fields has the same
> flexibility as separate profile model (since you can have only one).

You can have multiple subclasses of the User model (not that I recommend
subclassing).

> contrib.auth can be fairly simply adjusted to use custom User model
> from settings instead of always using its own User.

Yes, it could, but the entire ecosystem of reusable apps with FKs
pointing to contrib.auth.models.User can't.

> In that sense I am totally for homogenization because it will make
> code cleaner and eliminate unnecessary sql request not because of
> serialization.

Subclassing doesn't solve the extra SQL request unless the base User
model is turned into an abstract model, which would completely break
third-party FKs.

"Custom User model" is definitely a problem I'd like to see solved, but
to do it in a way that's backwards-compatible and allows reusable code
to point FKs at User is a difficult problem that will require adding
significant new indirection capabilities to the ORM, and no-one has yet
proposed a full solution AFAIK.

> Such code is really an eyesore:
> first_name = user.first_name
> middle_name = user.get_profile().middle_name
> last_name = user.last_name

I agree it's ugly, but if it bothers you it's fairly easy to wrap it up
into properties on your profile that proxy to the User model, and then
just always use your profile (you can even add a middleware that creates
a lazy-profile attribute directly on the request, if you want).

> What do you do in such situation? Create a profile class containing
> all required fields? And then if you update some app you need to
> update your composite UserProfile model?

Don't use AUTH_PROFILE_MODULE or .get_profile(). As far as I'm concerned
they bring almost nothing to the table except for the "there can be only
one" restriction, and I'd be just as happy to see them deprecated at
some point. The only justification I've heard for them is that they
allow reusable code to access the user profile, but I'm not sure what
reusable code is going to usefully do with a custom profile model when
it has no idea what properties it has.

Just use OneToOneField and the regular ORM access descriptors, and you
can have as many "user profiles" as you need.

Carl

Tom Evans

unread,
Mar 18, 2011, 11:06:11 AM3/18/11
to django-d...@googlegroups.com
On Fri, Mar 18, 2011 at 2:22 PM, Carl Meyer <ca...@oddbird.net> wrote:
>
>
> On 03/18/2011 08:09 AM, Alexander Schepanovski wrote:
>> I think using subclass of User model for your fields has the same
>> flexibility as separate profile model (since you can have only one).
>
> You can have multiple subclasses of the User model (not that I recommend
> subclassing).
>
>> contrib.auth can be fairly simply adjusted to use custom User model
>> from settings instead of always using its own User.
>
> Yes, it could, but the entire ecosystem of reusable apps with FKs
> pointing to contrib.auth.models.User can't.
>

Could one do something like this in contrib.auth.models:

from django.conf import settings

class BaseUser(models.Model):
#same as current User model except..
class Meta:
abstract = True

if hasattr(settings, 'USER_MODEL'):
import_model(settings.USER_MODEL)
User = settings.USER_MODEL
else:
class User(BaseUser):
pass

Then foreign keys would link to the 'right' user model. There might
have to be some magic with app_name..

Personally I prefer multiple profiles attached to the User model, but
I can see the appeal of a unified User/UserProfile in simple projects.

Cheers

Tom

Alexander Schepanovski

unread,
Mar 18, 2011, 9:01:19 PM3/18/11
to Django developers
On 18 мар, 21:22, Carl Meyer <c...@oddbird.net> wrote:
> On 03/18/2011 08:09 AM, Alexander Schepanovski wrote:
>
> > I think using subclass of User model for your fields has the same
> > flexibility as separate profile model (since you can have only one).
>
> You can have multiple subclasses of the User model (not that I recommend
> subclassing).
>
> > contrib.auth can be fairly simply adjusted to use custom User model
> > from settings instead of always using its own User.
>
> Yes, it could, but the entire ecosystem of reusable apps with FKs
> pointing to contrib.auth.models.User can't.
>
> > In that sense I am totally for homogenization because it will make
> > code cleaner and eliminate unnecessary sql request not because of
> > serialization.
>
> Subclassing doesn't solve the extra SQL request unless the base User
> model is turned into an abstract model, which would completely break
> third-party FKs.

I meaned making User model abstract the same way Tom Evans
demonstrated.
It can be still used with profiles.

> I agree it's ugly, but if it bothers you it's fairly easy to wrap it up
> into properties on your profile that proxy to the User model, and then
> just always use your profile (you can even add a middleware that creates
> a lazy-profile attribute directly on the request, if you want).

One should fix problem not hide it.

> Don't use AUTH_PROFILE_MODULE or .get_profile(). As far as I'm concerned
> they bring almost nothing to the table except for the "there can be only
> one" restriction, and I'd be just as happy to see them deprecated at
> some point. The only justification I've heard for them is that they
> allow reusable code to access the user profile, but I'm not sure what
> reusable code is going to usefully do with a custom profile model when
> it has no idea what properties it has.
>
> Just use OneToOneField and the regular ORM access descriptors, and you
> can have as many "user profiles" as you need.

I always construct single profile model for a project with fields
needed by all its apps. That's why I make my reusable apps provide
mixins and abstracts of profiles. I think profile model is redundant
itself, more of them even worse. It complicates code in many ways,
constructing a form for registration and edit profile is a good
example.

Ivan Sagalaev

unread,
Mar 19, 2011, 2:35:09 AM3/19/11
to django-d...@googlegroups.com
On 03/18/2011 07:22 AM, Carl Meyer wrote:
> Don't use AUTH_PROFILE_MODULE or .get_profile(). As far as I'm concerned
> they bring almost nothing to the table except for the "there can be only
> one" restriction

+1

> Just use OneToOneField and the regular ORM access descriptors, and you
> can have as many "user profiles" as you need.

True. Long ago I've coded a custom AutoOneToOneField[1] that implicitly
creates a dependent profile object on first access. It turned out to be
useful in many cases.

[1]:
http://bazaar.launchpad.net/~isagalaev/+junk/cicero/view/head:/fields.py#L19

Reply all
Reply to author
Forward
0 new messages