Ponytech

Technology for ponies

Mar 31, 2013

Migrate your user profile data to Django 1.5 custom user model

One of the major feature of Django 1.5 is the new custom user model. This article is a step by step guide on how to migrate your existing user data using the legacy user profile (which will be dropped in version 1.7) to a custom user model without losing data in the process.

This guide will use the excellent South framework to handle the migration. If you are not already using South, then you should! But don't worry, it's not too late to convert your project to South.

Initial set up

Let's suppose we have an app called myapp and the following model which allows us to store user's date of birth along with the user model:

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

class UserProfile(models.Model):
       user = models.ForeignKey(User, unique=True)
       birthdate = models.DateField('Date of birth', null=True)

And we use the deprecated user profile setting : AUTH_PROFILE_MODULE='myapp.UserProfile' . The aim of this article is to get rid of this extra model / table by integrating the birth date directly into the user model.

Convert project to South

First step is to convert the project to South. If you are already using South, you can skip to the next step. Install South with pip install south and add south to your INSTALLED_APPS. Converting your app is as easy as

./manage.py syncdb

./manage.py convert_to_south myapp

Prepare the migration

First create an empty MyUser model that ineherit from AbstractUser

from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
       pass

and create an empty schema migration :

./manage.py schemamigration myapp --empty rename_auth_user_to_myapp_my_user

This creates an empty schema migration file in myapp/migrations/ named 0002_rename_auth_user_to_myapp_my_user.py. Let's edit that file and just add rename instructions in order to easily maintain all our existing users:

def forwards(self, orm):
    db.rename_table('auth_user', 'myapp_myuser')

def backwards(self, orm):
    db.rename_table('myapp_myuser', 'auth_user')

Now we want that extra birthdate column for our user, so turn your empty MyUser model to:

class MyUser(AbstractUser):
       birthdate = models.DateField('Date of birth', null=True)

and make an auto migration to get the field added to the table:

./manage.py schemamigration myapp --auto

It is now time to actually copy the date of birth to the new model using a data migration. Start a new data migration with:

./manage.py datamigration myapp copy_birthdate

Edit the migration file 0004_copy_birthdate with:

def forwards(self, orm):
    for userprofile in orm['myapp.UserProfile'].objects.all():
        user = orm['myapp.MyUser'].objects.get(id=userprofile.user_id)
        user.birthdate = userprofile.birthdate
        user.save()

If you ever want to go back in your migrations list you have to copy birthdates from MyUser back to UserProfile in the backwards() method. I let you write this migration as an exercice!

Finally we can get rid of the UserProfile model / table. Remove this model from models.py and create one more auto schema migration:

./manage.py schemamigration myapp --auto

Migrate

To sum up you should have the following migration files in your migration folder:

  • 0001_initial.py
  • 0002_migrate_to_custom_user.py
  • 0003_auto__add_field_myuser_birthdate.py
  • 0004_copy_birthdate.py
  • 0005_auto__del_userprofile.py

Let's actually apply those migrations with:

./manage.py migrate myapp

And voila! You data had been converted to new custom user model. To make use of it remove AUTH_PROFILE_MODULE from your settings and replace it by AUTH_USER_MODEL = 'myapp.MyUser'.

For more info on how to use the cutom user model consult the django documentation.

Mar 05, 2013

Django 1.5 released

Django 1.5 had finally been released after two release candidates. Let's have a look in details of what it comes with.

It is the first Django version to support Python 3. This feature required a long work and is still considered experimental : do not use it in production. Django 1.6 is planned to be the release ready for Python 3 production. In the meantime, this 1.5 release let you start working on porting your app.

The other big features it adds is a configurable user model to exactly let your application tailor your needs in term of user's specific field or constraints. In previous versions you had to create a sperate table and link it to to the User model through user's profile to add information (facebook id, birthdate, etc) tied to your users. This feature is now deprecated in favor of the configurable user model. Also this new user model lets you specify different constraints. What if you want usernames to be 50 characters long ? This was simply not possible with prior django versions.

If you have models with a large number of fields and your are looking at some optimisations you may be interested by saving a subset of model’s fields. For example:

entry.title = 'New title'
entry.quthor = 'John Doe'

# only update author
entry.save(update_fields='author')

Other noteable additions concerns caching of related model instances, support for streaming responses, a new template tag to ease the use of Javascript in templates.

For an exhaustive list, consult the release notes

← Previous Page 3 of 3