How to Rename a Django App
Tags: intermediate, advanced, refactoring, django
Published: 2022-10-04 09:14:03

---
title: How to Rename a Django App
published: true
date: 2022-10-04 00:06:00 UTC
tags: Intermediate,Advanced,Refactoring,Django
canonical_url: http://djangotricks.blogspot.com/2022/10/how-to-rename-a-django-app.html
---

![How to Rename a Django App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xy0433ku8f1m5a6ezudh.png)

When I initially created my MVP (minimal viable product) for [1st things 1st](https://www.1st-things-1st.com), 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:

```shell
(venv)$ pip install django-rename-app
```

Put the app into `INSTALLED_APPS` in your settings:

```python
INSTALLED_APPS = [
    # …
    "django_rename_app",
]
```

## 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`:

```bash
(env)$ python manage.py rename_app oldapp newapp
```

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.

```bash
(env)$ python manage.py makemigrations newapp --empty --name rename_indexes
```

Fill the migration with the following code:

```python
# 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),
    ]
```

Run the migrations:

```bash
(env)$ python manage.py migrate
```

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:

```bash
(env)$ python manage.py migrate 0001
```

## 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](https://unsplash.com/photos/I_pOqP6kCOI).