Migrating existing auth.User data to new Django 1.5 custom user model? Migrating existing auth.User data to new Django 1.5 custom user model? postgresql postgresql

Migrating existing auth.User data to new Django 1.5 custom user model?


South is more than able to do this migration for you, but you need to be smart and do it in stages. Here's the step-by-step guide: (This guide presupposed you subclass AbstractUser, not AbstractBaseUser)

  1. Before making the switch, make sure that south support is enabled in the applicationthat contains your custom user model (for the sake of the guide, we'll call it accounts and the model User).At this point you should not yet have a custom user model.

    $ ./manage.py schemamigration accounts --initialCreating migrations directory at 'accounts/migrations'...Creating __init__.py in 'accounts/migrations'...Created 0001_initial.py.$ ./manage.py migrate accounts [--fake if you've already syncdb'd this app] Running migrations for accounts: - Migrating forwards to 0001_initial. > accounts:0001_initial - Loading initial data for accounts.
  2. Create a new, blank user migration in the accounts app.

    $ ./manage.py schemamigration accounts --empty switch_to_custom_userCreated 0002_switch_to_custom_user.py.
  3. Create your custom User model in the accounts app, but make sure it is defined as:

    class SiteUser(AbstractUser): pass
  4. Fill in the blank migration with the following code.

    # encoding: utf-8from south.db import dbfrom south.v2 import SchemaMigrationclass Migration(SchemaMigration):    def forwards(self, orm):        # Fill in the destination name with the table name of your model        db.rename_table('auth_user', 'accounts_user')        db.rename_table('auth_user_groups', 'accounts_user_groups')        db.rename_table('auth_user_user_permissions', 'accounts_user_user_permissions')    def backwards(self, orm):        db.rename_table('accounts_user', 'auth_user')        db.rename_table('accounts_user_groups', 'auth_user_groups')        db.rename_table('accounts_user_user_permissions', 'auth_user_user_permissions')    models = { ....... } # Leave this alone
  5. Run the migration

    $ ./manage.py migrate accounts - Migrating forwards to 0002_switch_to_custom_user. > accounts:0002_switch_to_custom_user - Loading initial data for accounts.
  6. Make any changes to your user model now.

    # settings.pyAUTH_USER_MODEL = 'accounts.User'# accounts/models.pyclass SiteUser(AbstractUser):    site = models.ForeignKey(Site, null=True)
  7. create and run migrations for this change

    $ ./manage.py schemamigration accounts --auto + Added field site on accounts.UserCreated 0003_auto__add_field_user_site.py.$ ./manage.py migrate accounts - Migrating forwards to 0003_auto__add_field_user_site. > accounts:0003_auto__add_field_user_site - Loading initial data for accounts.

Honestly, If you already have good knowledge of your setup and already use south, It should be as simple as adding the following migration to your accounts module.

# encoding: utf-8from south.db import dbfrom south.v2 import SchemaMigrationfrom django.db import modelsclass Migration(SchemaMigration):    def forwards(self, orm):        # Fill in the destination name with the table name of your model        db.rename_table('auth_user', 'accounts_user')        db.rename_table('auth_user_groups', 'accounts_user_groups')        db.rename_table('auth_user_permissions', 'accounts_user_permissions')        # == YOUR CUSTOM COLUMNS ==        db.add_column('accounts_user', 'site_id',            models.ForeignKey(orm['sites.Site'], null=True, blank=False)))    def backwards(self, orm):        db.rename_table('accounts_user', 'auth_user')        db.rename_table('accounts_user_groups', 'auth_user_groups')        db.rename_table('accounts_user_user_permissions', 'auth_user_user_permissions')        # == YOUR CUSTOM COLUMNS ==        db.remove_column('accounts_user', 'site_id')    models = { ....... } # Leave this alone

EDIT 2/5/13: added rename for auth_user_group table. FKs will auto update to point at the correct table due to db constraints, but M2M fields' table names are generated from the names of the 2 end tables and will need manual updating in this manner.

EDIT 2: Thanks to @Tuttle & @pix0r for the corrections.


My incredibly lazy way of doing this:

  1. Create a new model (User), extending AbstractUser. Within new model, in it's Meta, override db_table and set to 'auth_user'.

  2. Create an initial migration using South.

  3. Migrate, but fake the migration, using --fake when running migrate.

  4. Add new fields, create migration, run it normally.

This is beyond lazy, but works. You now have a 1.5 compliant User model, which just uses the old table of users. You also have a proper migration history.

You can fix this later on with manual migrations to rename the table.


I think you've correctly identified that a migration framework like South is the right way to go here. Assuming you're using South, you should be able to use the Data Migrations functionality to port the old users to your new model.

Specifically, I would add a forwards method to copy all rows in your user table to the new table. Something along the lines of:

def forwards(self, orm):    for user in orm.User.objects.all():        new_user = SiteUser(<initialize your properties here>)        new_user.save()

You could also use the bulk_create method to speed things up.