Blog Tags: 

Django User Profiles - Simple yet powerful

So you're building a web application, and using the excellent contrib.auth subsystem to manage user accounts. Most probably you need to store additional information about your users, but how? Django profiles to the rescue!

Django provides a lightweight way of defining a profile object linked to a given user. The profile object can differ from project to project, and it can even handle different profiles for different sites served from the same database.

In a nutshell, using Django profiles consists of 3 steps:

  • Define a model that holds the profile information.
  • Tell Django where to look for the profile object.
  • Create the user profile as needed.

 

Defining the user profile model

The only requirement Django places on this model is that it have a unique ForeignKey to the User model, and is called user. Other than that, you can define any other fields you like.

For our example, we'll create 2 user profile fields (url and company).

account/models.py

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    url = models.URLField("Website", blank=True)
    company = models.CharField(max_length=50, blank=True)

 

Tell Django about the profile object

Accessing a users profile is done by calling user.get_profile(), but in order to use this function, Django needs to know where to look for the profile object.

This is defined in the projects settings.py file.

AUTH_PROFILE_MODULE = "account.UserProfile"

Important note: The settings value is appname.modelname, and not appname.models.modelname as you might expect. The reason for this is that Django is not doing a direct import, but using an internal model-loading function.

Once defined, and if the profile exists, accessing a users profile is simple.

foo/views.py

@login_required
def view_foo(request):
    user_profile = request.user.get_profile()
    url = user_profile.url

    #OR
    url = request.user.get_profile().url

 

Create the user profile as needed

Notice in the section above I mentioned "if the profile exists". This is because the get_profile() function will raise a DoesNotExist exception if the profile does not exist.

One of the common solutions to this issue is to create the profile when a user is registered using a signal (see my post on Django Signals).

Another option is catch the exception, and redirect the user to a profile creation form. You usually want to do this if the profile fields are mandatory.

My personal favorite though, is to have the profile created automatically when referenced, with the added bonus of being able to reference a users profile as user.profile instead of user.get_profile()

account/models.py

...
class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    ...

User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

 

To reiterate, including the above enables us to reference the users profile with cleaner code, and have it created if it does not exist.

foo/views.py

@login_required
def view_foo(request):
    url = request.user.profile.url

 

Ever needed to store additional user information? Post a comment!

Comments

Alon Swartz's picture

Thanks for the feedback. I'm not quite sure what you mean, Django User Profiles are a simple way to associate additional information to your user accounts. If you need to associate other models to a user account, then you should use a foreign key.

foo/models.py

from django.db import models
from django.contrib.auth.models import User

class Foo(models.Model):
    user = models.ForeignKey(User)
    stuff = models.CharField(max_length=50)
    ...

You could then refer to the associated user foo's with something like this:

foo/views.py

from django.contrib.auth.decorators import login_required

@login_required
def bar(request):
    foos = request.user.foo_set.all()  # or any of the other useful methods
    ...

I hope the above helps, if not, the more info you can provide, the easier it will be to help.

Alon Swartz's picture

You really should look into using a contrib module to handle user creation for you (such as django-registration), but I suppose it depends on your use-case.

Anyway, hopefully the below code snippet will help you get started.

user = User.objects.create_user('bob', 'bob@example.com', 'password')
user.first_name = "Bob"
user.last_name = "Smith"
user.save()

user_profile = user.get_profile()
user_profile.display_name = "Bob Smith"
user_profile.save()

My guess is you forgot to call save() on the object you created, which is required to write the changes to the database.

Also note that I used first_name and last_name as an alternative to "display_name", that's usually how you store account names in Django, you can then access the fullname like this:

user.get_full_name()

I hope the above helps...

Alon Swartz's picture

You don't need step 2, actually you must not do anything like step 2 if you want to use contrib.auth

You also don't need to create first/last name fields as you mentioned in step 3 as contrib.auth.models.User already has them. See my comment above for more details on that.

You also don't need step 4, contrib.auth handles that for you.

Regarding step 5, I'm don't think using a tuple will work. It should be a string, see the post for an example.

I'd recommend re-reading the post a couple of times, and if something isn't clear let me know and I'll elaborate. If something isn't working, feel free to ask and include code snippets.

dpbklyn's picture

@Szubi,

Can you please walk me through the URLs file you mention above, I am not sure I understand what each part does.

Thank you,

dp

dpbklyn's picture

I am steppig through your process and it is all (slowly) becomming clear to me.

Pages

Add new comment