DEV Community

Aidas Bendoraitis
Aidas Bendoraitis

Posted on • Originally published at djangotricks.com on

How to Rename a Django App

How to Rename a Django App

When I initially created my MVP (minimal viable product) for 1st things 1st, I considered the whole Django project to be about prioritization. After a few years, I realized that the Django project is about SaaS (software as a service), and prioritization is just a part of all functionalities necessary for a SaaS to function. I ended up needing to rename apps to have clean and better-organized code. Here is how I did that.

0. Get your code and database up to date

Ensure you have the latest git pull and execute all database migrations.

1. Install django-rename-app

Put django-rename-app into pip requirements and install them or just run:

(venv)$ pip install django-rename-app 
Enter fullscreen mode Exit fullscreen mode

Put the app into INSTALLED_APPS in your settings:

INSTALLED_APPS = [ # …  "django_rename_app", ] 
Enter fullscreen mode Exit fullscreen mode

2. Rename the app directories

Rename the oldapp as newapp in your apps and templates.

3. Rename the app name occurrences in the code

Rename the app in all your imports, relations, migrations, and template paths.

You can do a global search for oldapp and then check case by case where you need to rename that term to newapp, and where not.

4. Run the management command rename_app

Run the management command rename_app:

(env)$ python manage.py rename_app oldapp newapp 
Enter fullscreen mode Exit fullscreen mode

This command renames the app prefix the app tables and the records in django_content_type and django_migrations tables.

If you plan to update staging or production servers, add the rename_app command before running migrations in your deployment scripts (Ansible, Docker, etc.)

5. Update indexes and constraints

Lastly, create an empty database migration for the app with custom code to update indexes and foreign-key constraints.

(env)$ python manage.py makemigrations newapp --empty --name rename_indexes 
Enter fullscreen mode Exit fullscreen mode

Fill the migration with the following code:

# newapp/migrations/0002_rename_indexes.py from django.db import migrations def named_tuple_fetch_all(cursor): "Return all rows from a cursor as a namedtuple" from collections import namedtuple desc = cursor.description Result = namedtuple("Result", [col[0] for col in desc]) return [Result(*row) for row in cursor.fetchall()] def rename_indexes(apps, schema_editor): from django.db import connection with connection.cursor() as cursor: cursor.execute( """SELECT indexname FROM pg_indexes WHERE tablename LIKE 'newapp%'""" ) for result in named_tuple_fetch_all(cursor): old_index_name = result.indexname new_index_name = old_index_name.replace( "oldapp_", "newapp_", 1 ) cursor.execute( f"""ALTER INDEX IF EXISTS {old_index_name} RENAME TO {new_index_name}""" ) def rename_foreignkeys(apps, schema_editor): from django.db import connection with connection.cursor() as cursor: cursor.execute( """SELECT table_name, constraint_name FROM information_schema.key_column_usage WHERE constraint_catalog=CURRENT_CATALOG AND table_name LIKE 'newapp%' AND position_in_unique_constraint notnull""" ) for result in named_tuple_fetch_all(cursor): table_name = result.table_name old_foreignkey_name = result.constraint_name new_foreignkey_name = old_foreignkey_name.replace( "oldapp_", "newapp_", 1 ) cursor.execute( f"""ALTER TABLE {table_name} RENAME CONSTRAINT {old_foreignkey_name} TO {new_foreignkey_name}""" ) class Migration(migrations.Migration): dependencies = [ ("newapp", "0001_initial"), ] operations = [ migrations.RunPython(rename_indexes, migrations.RunPython.noop), migrations.RunPython(rename_foreignkeys, migrations.RunPython.noop), ] 
Enter fullscreen mode Exit fullscreen mode

Run the migrations:

(env)$ python manage.py migrate 
Enter fullscreen mode Exit fullscreen mode

If something doesn't work as wanted, migrate back, fix the code, and migrate again. You can unmigrate by migrating to one step before the last migration, for example:

(env)$ python manage.py migrate 0001 
Enter fullscreen mode Exit fullscreen mode

6. Cleanup

After applying the migration in all necessary environments, you can clean them up by removing django-rename-app from your pip requirements and deployment scripts.

Final words

It's rarely possible to build a system that meets all your needs from the beginning. Proper systems always require continuous improvement and refactoring. Using a combination of Django migrations and django-rename-app, you can work on your websites in an Agile, clean, and flexible way.

Happy coding!


Cover photo by freestocks.

Top comments (0)