Published on: 11/12/2010 00:20h
Django brings a built-in user authentication system, it includes an User model which has the most common attributes. But in most applications you may need to store additional attributes to users. Django has a way to do this too.
Extending using foreign key
Basically you create your
UserProfile model with a
class UserProfile(models.Model): user = models.OneToOneField('auth.User') bio = models.TextField() # ...
and define in on settings.py
AUTH_PROFILE_MODULE = 'accounts.UserProfile' # app name (dot) model name
From now on your
User objects will have a
I personally can’t see a reason to use this setting (and I hate “getters” methods), you just need to do this:
class UserProfile(models.Model): user = models.OneToOneField('auth.User', related_name='profile') bio = models.TextField() # ...
related_name='profile' parameter, now you don’t need the
get_profile() method anymore, just use
But there is a small problem here, if the user instance don’t have a profile related to it you will receive an
ObjectDoesNotExist exception. This happens with
get_profile() too. And it’s not good to handle the exception every time you access the profile. The simplest way to solve this is connect to
django.db.models.signals.post_save on the
User model and create your
UserProfile instance related to it
from django.db.models import signals from accounts.models import UserProfile def create_user_profile(sender, instance, created, **kwargs): if created: UserProfile.objects.create(user=instance) signals.post_save.connect(create_user_profile, sender=User)
Why subclassing User is a bad idea
There are a few reasons I prefer to create user profiles as another model instead of just subclassing the default User. If you think for a while, an user has a lot to do in your site, and there are at a few default steps:
- first she needs to register, confirm by email, and so on
- login and logout, change and reset password
- admins may need to manage groups and permissions, to restrict user actions, offer features to specific groups
- manage profile, with personal information
Django doesn’t handle the first topic, there is a great app to handle registration.
The second and third topics can be done with
django.contrib.auth app, this is exactly it’s purpose.
And then you have the forth topic, which is profiles. As you can see, it can be done as a separate app. A user has a profile. So makes sense to have a
profile attribute in the User object.
If you split features in apps like this it’s easier to reuse too, that’s the idea of django apps after all! The django-registration is an example. And as you can imagine, there are apps to manage profiles too.
Editing User profile in admin
If you’re using admin you may want to edit the UserProfile fields in the same page as the User fields, and it’s possible using admin inlines. Here is how you admin configuration will look like:
from django.contrib import admin from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin from django.contrib.auth.models import User from accounts.models import UserProfile class UserProfileInline(admin.TabularInline): model = UserProfile class UserAdmin(DjangoUserAdmin): inlines = (UserProfileInline,) admin.site.unregister(User) admin.site.register(User, UserAdmin)
As you can see, it quite easy to manage user profiles in django. Although there is a way to hook you profile model in settings.py, you can do it with a simple foreign key. And as usual, there are a few reusable apps around to handle the generic stuff.
By Igor Sobreira