DEV Community

Achraf Ben Hamou
Achraf Ben Hamou

Posted on

How to Rename a Django Application Safely

Renaming a Django application looks simple at first: rename the directory and update the imports.

However, if the application already has migrations and data in production, renaming it can be tricky. Django uses the application name in several places, including migration history, content types, permissions, and database table names.

In this article, we'll look at a safe way to rename a Django app, especially when using PostgreSQL.


The important distinction: package name vs. app label

Before changing anything, it's important to understand that Django has several concepts related to an app's name.

For example:

myproject/
├── manage.py
├── config/
└── foo/
    ├── __init__.py
    ├── apps.py
    ├── models.py
    └── migrations/
Enter fullscreen mode Exit fullscreen mode

The Python package is:

foo
Enter fullscreen mode Exit fullscreen mode

And the application configuration might be:

from django.apps import AppConfig


class FooConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "foo"
Enter fullscreen mode Exit fullscreen mode

Django also has an app label, which is used internally by migrations and content types.

By default, the app label is derived from the last part of name.

This distinction is important because changing the Python package name does not necessarily mean that you need to change the Django app label.


Option 1: Rename only the Python package

If your main goal is to rename:

foo/
Enter fullscreen mode Exit fullscreen mode

to:

bar/
Enter fullscreen mode Exit fullscreen mode

while keeping the existing Django application identity, this is usually the safest approach.

Rename the directory:

foo/
Enter fullscreen mode Exit fullscreen mode

to:

bar/
Enter fullscreen mode Exit fullscreen mode

Then update apps.py:

from django.apps import AppConfig


class BarConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "bar"
    label = "foo"
Enter fullscreen mode Exit fullscreen mode

The important part here is:

label = "foo"
Enter fullscreen mode Exit fullscreen mode

By keeping the old label, Django continues to recognize the application as the same application from the migration/content-type perspective.

Then update your imports and references:

from foo.models import MyModel
Enter fullscreen mode Exit fullscreen mode

becomes:

from bar.models import MyModel
Enter fullscreen mode Exit fullscreen mode

Also check:

  • INSTALLED_APPS
  • apps.py
  • urls.py
  • views.py
  • admin.py
  • forms.py
  • signals.py
  • Celery configuration
  • tests
  • templates
  • static files
  • management commands
  • any imports elsewhere in the project

For example:

INSTALLED_APPS = [
    # ...
    "bar.apps.BarConfig",
]
Enter fullscreen mode Exit fullscreen mode

With this approach, you generally don't need to manually modify django_content_type or django_migrations.

This is usually the preferred solution when you simply want to rename the Python package.


Option 2: Change the Django app label as well

Sometimes you don't only want:

foo/
Enter fullscreen mode Exit fullscreen mode

to become:

bar/
Enter fullscreen mode Exit fullscreen mode

You also want Django to consider the application itself to have changed from:

foo
Enter fullscreen mode Exit fullscreen mode

to:

bar
Enter fullscreen mode Exit fullscreen mode

This is much more complicated.

For example, Django's default database table name for:

class Customer(models.Model):
    ...
Enter fullscreen mode Exit fullscreen mode

may be:

foo_customer
Enter fullscreen mode Exit fullscreen mode

If the app label changes to bar, Django may expect:

bar_customer
Enter fullscreen mode Exit fullscreen mode

You therefore need to consider:

  1. Migration history
  2. Content types
  3. Permissions
  4. Database tables
  5. Foreign keys and many-to-many tables
  6. Generic relations
  7. Existing migration files
  8. Third-party packages referencing the old app label

Don't blindly edit django_migrations

A common solution found online is:

UPDATE django_migrations
SET app = 'bar'
WHERE app = 'foo';
Enter fullscreen mode Exit fullscreen mode

Although this can be useful in very specific migration-management procedures, it should not be treated as the standard first step for renaming a Django application.

The django_migrations table represents Django's migration history. Its contents must remain consistent with the migration files that Django loads.

Simply changing this table without carefully changing the migration graph can result in:

  • migrations being considered unapplied;
  • migrations being applied twice;
  • broken migration dependencies;
  • inconsistent production databases.

In other words, changing the database record alone does not rename a Django application.


What about django_content_type?

Django stores content types using the application's app_label.

For example:

app_label = foo
model = customer
Enter fullscreen mode Exit fullscreen mode

If the app label really changes to bar, existing content types may need to be updated:

UPDATE django_content_type
SET app_label = 'bar'
WHERE app_label = 'foo';
Enter fullscreen mode Exit fullscreen mode

However, this should be done only if you are intentionally changing the Django app label.

You should also consider the permissions associated with these content types.

Before doing this on production, always take a database backup and test the complete migration on a copy of the production database.


Renaming database tables

If your models use Django's default table names, changing the app label can also change the table names Django expects.

For example:

foo_customer
Enter fullscreen mode Exit fullscreen mode

could become:

bar_customer
Enter fullscreen mode Exit fullscreen mode

With PostgreSQL, a table can be renamed with:

ALTER TABLE foo_customer RENAME TO bar_customer;
Enter fullscreen mode Exit fullscreen mode

For several tables:

ALTER TABLE foo_customer RENAME TO bar_customer;
ALTER TABLE foo_order RENAME TO bar_order;
Enter fullscreen mode Exit fullscreen mode

However, don't assume that every model uses <app_label>_<model_name>.

A model can define its own database table:

class Customer(models.Model):
    class Meta:
        db_table = "customers"
Enter fullscreen mode Exit fullscreen mode

In this case, renaming the Django app does not require renaming the customers table.

So before writing SQL, inspect your actual database schema.


A safer migration approach

If you really need to change the app label and database table names, database changes should preferably be represented explicitly in Django migrations.

For example, you can use SeparateDatabaseAndState when the database operation and Django's model state need to be handled separately.

A simplified example:

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        # Your actual migration dependency
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=[
                migrations.RunSQL(
                    "ALTER TABLE foo_customer RENAME TO bar_customer;",
                    reverse_sql=(
                        "ALTER TABLE bar_customer "
                        "RENAME TO foo_customer;"
                    ),
                ),
            ],
            state_operations=[
                # Django state operations go here.
            ],
        ),
    ]
Enter fullscreen mode Exit fullscreen mode

The exact migration depends heavily on the existing project and migration history, so this should not be copied blindly into a production project.


Creating an empty migration

The original article contains a small syntax error here.

The correct command is:

python manage.py makemigrations bar --empty
Enter fullscreen mode Exit fullscreen mode

or:

./manage.py makemigrations bar --empty
Enter fullscreen mode Exit fullscreen mode

Notice that --empty is one option.

Not:

makemigrations bar - empty
Enter fullscreen mode Exit fullscreen mode

Be careful with migration dependencies

Another important issue is migration dependencies.

For example:

class Migration(migrations.Migration):
    dependencies = [
        ("bar", "0020_auto_20230530_1535"),
    ]
Enter fullscreen mode Exit fullscreen mode

This is only valid if Django actually has an application with the label bar and a migration named:

0020_auto_20230530_1535
Enter fullscreen mode Exit fullscreen mode

You should never simply replace:

("foo", "0020_...")
Enter fullscreen mode Exit fullscreen mode

with:

("bar", "0020_...")
Enter fullscreen mode Exit fullscreen mode

without understanding how Django's migration graph will change.

Existing migrations also contain dependencies such as:

dependencies = [
    ("foo", "0019_previous_migration"),
]
Enter fullscreen mode Exit fullscreen mode

If you rename the application label, these historical dependencies need to be handled consistently.


A practical recommendation

For most projects, I recommend the following strategy.

If you only want to rename the Python package

Use:

foo/ → bar/
Enter fullscreen mode Exit fullscreen mode

and keep:

label = "foo"
Enter fullscreen mode Exit fullscreen mode

in AppConfig.

Then update imports and application references.

This minimizes the risk of breaking your migration history.

If you absolutely need the Django app label to change

Treat it as a database and migration migration, not simply as a folder rename.

Before making the change:

  1. Back up the database.
  2. Test the operation on a copy of production.
  3. Inspect all existing migrations.
  4. Identify all database tables belonging to the application.
  5. Check django_content_type.
  6. Check permissions.
  7. Check generic foreign keys.
  8. Check third-party applications that reference the old app label.
  9. Plan the migration graph carefully.
  10. Deploy the database changes together with the corresponding application code.

Conclusion

Renaming a Django application is not just a matter of renaming a directory.

The safest solution depends on what you actually want to rename:

Python package
      ↓
foo/ → bar/
Enter fullscreen mode Exit fullscreen mode

is relatively straightforward.

But changing:

Django app label
      ↓
foo → bar
Enter fullscreen mode Exit fullscreen mode

can affect migrations, content types, permissions and database tables.

Therefore, before manually modifying tables such as:

django_migrations
django_content_type
Enter fullscreen mode Exit fullscreen mode

make sure you understand which Django identity you are changing.

For an existing production application, keeping the original app label while renaming the Python package is often the least risky solution.

And, as always, test the complete procedure against a copy of your production database before deploying it.

Thanks for reading!

Top comments (0)