Migrating to Django 1.5 and Custom User Model

on March 28, 2013 in technology about

With the recent Django 1.5 release, we now have the choice to create custom user model instead of the default user model that came with django.contrib.auth.

Two important use cases this release resolved were the ability to easily extend user profile and fix User.email field from having a hard coded value of max_length=75. This isn’t in compliant with RFC 5321, which establishes that an email can have max_length=254.

Here are a few quick steps to migrate your current users and profiles to take advantage of the new custom user model feature in Django 1.5 release.

Create a new Django app

We’ll call this app accounts for the rest of this article. You’re definitely free to call it whatever you want. You can call it humans for instance.

django-admin.py startapp accounts

Duplicate old User object definitions

Copy django.contrib.auth.models.User object into accounts.models.User. Doing this would make our later migrations much simpler. You can definitely make additional changes after the transition away from old User object finalizes.

Move your profile model into accounts

If you’re like me, you probably had a Profile or UserProfile object to extend the legacy User object. It made sense then because you didn’t want to modify the django.contrib.auth source codes.

With Django 1.5, this decision is a matter of preference. However, I would recommend keeping a profile model to hold attributes not relating to basic User object’s goals of keeping authentication & essential information.

Use South to make initial migration

python manage.py schemamigration accounts --initial

Migrate accounts models

python manage.py migrate accounts

Remove and rename database tables

Drop the newly migrated accounts.models.User and relational objects and rename the old django.contrib.auth.models.User to it. You could certainly do the following step in South if you want a choice to revert this change.

# delete and rename the User object and its relational tables
DROP TABLE accounts_users;
RENAME TABLE auth_user TO accounts_users;
DROP TABLE accounts_users_groups;
RENAME TABLE auth_user_groups TO accounts_users_groups;
DROP TABLE accounts_users_user_permissions;
RENAME TABLE auth_user_user_permissions TO accounts_users_user_permissions;

# delete and rename the profile tables
DROP TABLE accounts_profiles;
RENAME TABLE user_profiles TO accounts_profiles;

# if you want to (or already) immediately changed email field from 75 to 255 characters
ALTER TABLE accounts_users MODIFY username VARCHAR(255);
ALTER TABLE accounts_users MODIFY email VARCHAR(255);

Fix references to old User object

Replacing old imports with the correct reference to the new User object with the get_user_model utility method.

# old
from django.contrib.auth.models import User

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

WARNING: You probably should run South migration on all apps to make sure other models are aware of the new User object.

You can now make any further changes to your new User object. Good luck!