Extending the Django User Model

Django provides a very powerful user system out of the box but since it has to be generic enough to ship with the framework they don't provide a lot of extra fields to store additional information about your users, that is left up to you as the developer.

Django doesn't leave you hanging though, they provide all the tools you need to easily and quickly extend the included model.

The first thing you need to do is define a model with a foreign key to the base user model with all the additional information you would like to store:

from django.db import models

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    company = models.CharField(max_length=255, blank=True, null=True)
    nickname = models.CharField(max_length=255, blank=True, null=True)

After that you need to tell Django about your profile model in settings.py:

AUTH_PROFILE_MODULE='app.UserProfile'

Now you can call get_profile() on any user instance and it will return the matching UserProfile instance but you need to make sure you actually create the profile when you create the user.

The first way to do this is to attach post_save and post_delete signals:

from django.db import models

def user_post_delete(sender, instance, **kwargs):
    try:
        UserProfile.objects.get(user=instance).delete()
    except:
        pass

def user_post_save(sender, instance, **kwargs):
    try:
        profile, new = UserProfile.objects.get_or_create(user=instance)
    except:
        pass

models.signals.post_delete.connect(user_post_delete, sender=User)
models.signals.post_save.connect(user_post_save, sender=User)

Check out the Django documentation for signals here

The one big flaw with that approach is that you don't actually have access to any of the UserProfile additional information so you need to provide default values or allow all fields to be null. If you want the ability to require certain fields in a profile you'll need to handle the creation in your form itself.

To override the built in UserCreationForm and adding your profile fields you just inherit from it and then override the save method:

from django.contrib.auth.forms import UserCreationForm

class UserForm(UserCreationForm):
    nickname = forms.CharField(required=True)
    company = forms.CharField(required=True)

    def save(self, commit=False):
        user = super(UserForm, self).save(commit=False) 
        user.save()

        try:
            profile = user.get_profile()
        except:
            profile = UserProfile(user=user)

        profile.nickname = self.cleaned_data['nickname'']
        profile.company = self.cleaned_data['company']
        profile.save()

        return user

Another quick little trick is to use python's property() method to define a profile property directly on your model. This will solve the issue of having to create your profile when you create the user but still has the issue that your additional fields can't be required:

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

Now that you have created the property on the model you no longer need to call get_profile(), you can access the profile directly:

from django.contrib.auth.models import User
user = User.objects.get(pk=1)
user.profile.nickname = 'nickname'

The biggest flaw with this implementation is that it makes a database query every time you access the profile property, so you will want to implement some sort of caching.

For more information on storing additional information about users in Django you can check out the documentation here.