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/
The Python package is:
foo
And the application configuration might be:
from django.apps import AppConfig
class FooConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "foo"
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/
to:
bar/
while keeping the existing Django application identity, this is usually the safest approach.
Rename the directory:
foo/
to:
bar/
Then update apps.py:
from django.apps import AppConfig
class BarConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "bar"
label = "foo"
The important part here is:
label = "foo"
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
becomes:
from bar.models import MyModel
Also check:
INSTALLED_APPSapps.pyurls.pyviews.pyadmin.pyforms.pysignals.py- Celery configuration
- tests
- templates
- static files
- management commands
- any imports elsewhere in the project
For example:
INSTALLED_APPS = [
# ...
"bar.apps.BarConfig",
]
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/
to become:
bar/
You also want Django to consider the application itself to have changed from:
foo
to:
bar
This is much more complicated.
For example, Django's default database table name for:
class Customer(models.Model):
...
may be:
foo_customer
If the app label changes to bar, Django may expect:
bar_customer
You therefore need to consider:
- Migration history
- Content types
- Permissions
- Database tables
- Foreign keys and many-to-many tables
- Generic relations
- Existing migration files
- 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';
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
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';
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
could become:
bar_customer
With PostgreSQL, a table can be renamed with:
ALTER TABLE foo_customer RENAME TO bar_customer;
For several tables:
ALTER TABLE foo_customer RENAME TO bar_customer;
ALTER TABLE foo_order RENAME TO bar_order;
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"
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.
],
),
]
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
or:
./manage.py makemigrations bar --empty
Notice that --empty is one option.
Not:
makemigrations bar - empty
Be careful with migration dependencies
Another important issue is migration dependencies.
For example:
class Migration(migrations.Migration):
dependencies = [
("bar", "0020_auto_20230530_1535"),
]
This is only valid if Django actually has an application with the label bar and a migration named:
0020_auto_20230530_1535
You should never simply replace:
("foo", "0020_...")
with:
("bar", "0020_...")
without understanding how Django's migration graph will change.
Existing migrations also contain dependencies such as:
dependencies = [
("foo", "0019_previous_migration"),
]
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/
and keep:
label = "foo"
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:
- Back up the database.
- Test the operation on a copy of production.
- Inspect all existing migrations.
- Identify all database tables belonging to the application.
- Check
django_content_type. - Check permissions.
- Check generic foreign keys.
- Check third-party applications that reference the old app label.
- Plan the migration graph carefully.
- 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/
is relatively straightforward.
But changing:
Django app label
↓
foo → bar
can affect migrations, content types, permissions and database tables.
Therefore, before manually modifying tables such as:
django_migrations
django_content_type
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)