Skip to content

Using Configurable User Models in Django 1.5

Posted on:November 29, 2012

Django users take for granted the ability to configure your own user model but prior to Django 1.5 you were stuck with Django’s predefined User model. If you want to take advantage of this new functionality then keep on reading as I’ll go through how to migrate your current application to the new configurable user model.

Getting Started

Getting Started

For the sake of simplicity let’s make our own User object that is exactly the same as Django’s current but fixes the email max_length field to comply with RFC 5321 of 254 characters and adds a required field for the user’s twitter handle.

# myapp.models.py
from django.contrib.auth.models import AbstractBaseUser

class MyUser(AbstractBaseUser):
    username = models.CharField(max_length=40, unique=True, db_index=True)
    email = models.EmailField(max_length=254, unique=True)
    twitter_handle = models.CharField(max_length=255)
    ...

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['twitter_handle']

You’ll notice a few new things about this:

Inheriting AbstractBaseUser: This adds a few helper fields such as password and last_login as well as methods for setting the user’s password, getting the username, checking if the user is active. You can check out a full list of what it includes here.

USERNAME_FIELD: This is a string describing the name of the field on the User model that is used as the unique identifier. This will usually be a username of some kind, but it can also be an email address or any other unique identifier.

REQUIRED_FIELDS: A list of the field names that must be provided when creating a user. REQUIRED_FIELDS must contain all required fields on your User model, but should not contain the USERNAME_FIELD.

Now that you’ve created your User model you have to tell Django that you want to use it instead of their default User model. To do this you add the following to your settings file:

# settings.py
AUTH_USER_MODEL = 'myapp.MyUser'

With this setting Django now knows which User model to use.

Using Foreign Keys

Using Foreign Keys

Once you’ve set up your model its now time reference it in other models.

from django.conf import settings
from django.db import models

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL)

This tells Django to create a ForeignKey to the User model that you specify in your settings.

Custom Manager

Custom Manager

Now that you’ve created your own User model you also need to create your own Manager to handle the creation of Users and Super Users. If your User model defines the same fields as Django’s default User you can just install Django’s UserManager.

from django.contrib.auth.models import UserManager, AbstractBaseUser

class MyUser(AbstractBaseUser):
    ...
    objects = UserManager

If your User model includes different fields you’ll need to define your own custom manager that extends BaseUserManager.

from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

class MyUserManager(BaseUserManager):
    def create_user(self, email, twitter_handle, password=None):
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=MyUserManager.normalize_email(email),
            twitter_handle=twitter_handle,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, twitter_handle, password):
        user = self.create_user(email,
            password=password,
            twitter_handle=twitter_handle
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class MyUser(AbstractBaseUser):
    ...
    objects = MyUserManager

Other Methods

Other Methods

There are a few other methods you need to include:

get_full_name: A longer formal identifier for the user. A common interpretation would be the full name of the user, but it can be any string that identifies the user.

get_short_name: A short, informal identifier for the user. A common interpretation would be the first name of the user, but it can be any string that identifies the user in an informal way.

is_active: A boolean attribute that indicates whether the user is considered “active”. This attribute is provided as an attribute on AbstractBaseUser defaulting to True.

Final Example

Final Example
# models.py
from django.conf import settings
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

class MyUserManager(BaseUserManager):
    def create_user(self, email, twitter_handle, password=None):
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=MyUserManager.normalize_email(email),
            twitter_handle=twitter_handle,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, twitter_handle, password):
        user = self.create_user(email,
            password=password,
            twitter_handle=twitter_handle,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class MyUser(AbstractBaseUser):
    email = models.EmailField(max_length=254, unique=True, db_index=True)
    twitter_handle = models.CharField(max_length=255)

    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['twitter_handle']

    def get_full_name(self):
        # For this case we return email. Could also be User.first_name User.last_name if you have these fields
        return self.email

    def get_short_name(self):
        # For this case we return email. Could also be User.first_name if you have this field
        return self.email

    def __unicode__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        # Handle whether the user has a specific permission?"
        return True

    def has_module_perms(self, app_label):
        # Handle whether the user has permissions to view the app `app_label`?"
        return True

    @property
    def is_staff(self):
        # Handle whether the user is a member of staff?"
        return self.is_admin


class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL)


#views.py
from django.contrib.auth import get_user_model
...
User = get_user_model()

Related Posts