Skip to content

Instantly share code, notes, and snippets.

@jamesmfriedman
Last active February 8, 2022 18:56
Show Gist options
  • Save jamesmfriedman/6168003 to your computer and use it in GitHub Desktop.
Save jamesmfriedman/6168003 to your computer and use it in GitHub Desktop.
Renaming a Django app that has migrations already sucks. This Is a way I found to do it that preserves your old migration history and keeps your contenttypes in order. The trick is, this migration cannot be in the app you are migrating, so stick it in your "core" app or another app you have installed. Just plug in your own old and new app names.
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
from django.db.models import get_app, get_models
class Migration(SchemaMigration):
# old_name => new_name
apps_to_rename = {
'some_old_app' : 'some_new_app',
'another_old_app' : 'another_new_app'
}
def forwards(self, orm):
for old_appname, new_appname in self.apps_to_rename.items():
# Renaming model from 'Foo' to 'Bar'
db.execute("UPDATE south_migrationhistory SET app_name = %s WHERE app_name = %s", [new_appname, old_appname])
db.execute("UPDATE django_content_type SET app_label = %s WHERE app_label = %s", [new_appname, old_appname])
app = get_app(new_appname)
for model in get_models(app, include_auto_created=True):
if model._meta.proxy == True:
continue
new_table_name = model._meta.db_table
old_table_name = old_appname + new_table_name[len(new_appname):]
db.rename_table(old_table_name, new_table_name)
def backwards(self, orm):
for old_appname, new_appname in self.apps_to_rename.items():
# Renaming model from 'Foo' to 'Bar'
db.execute("UPDATE south_migrationhistory SET app_name = %s WHERE app_name = %s", [old_appname, new_appname])
db.execute("UPDATE django_content_type SET app_label = %s WHERE app_label = %s", [old_appname, new_appname])
app = get_app(new_appname)
for model in get_models(app, include_auto_created=True):
if model._meta.proxy == True:
continue
old_table_name = model._meta.db_table
new_table_name = old_appname + old_table_name[len(new_appname):]
db.rename_table(old_table_name, new_table_name)
@jason-curtis
Copy link

Careful with this one. Relying on django.db.models from within a migration is dangerous because there is no guarantee that the models you get from get_models() are actually in the database at the moment.
If you have unapplied migrations in the app you're renaming, this migration may try to rename tables that don't exist yet.

@robertlagrant
Copy link

Could you instead get the models by querying based on the table's name, and filtering to only show ones that start with the app name?

@zBeeble42
Copy link

What I don't get from this post is an overall order-of-operations. When do I move the files (models, views, etc) from the old to the new? When can I delete the old safely? In my case, I have an app that I wrote called pages and I have a need to import mezzanine ... which has a sub-app called pages. So I need to rename my pages app to be able to use mezzanine.

@TurnrDev
Copy link

@zBeeble42 that's why you should avoid generic names in future

@wasabigeek
Copy link

wasabigeek commented Feb 25, 2018

@zBeeble42 instead of renaming your app, would you be able to use aliasing? e.g. from mezzanine import pages as mezzpages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment