How to rename Django application

Not always you have project structure perfect right from the start. Probably never actually. And during development you might realise that your application named "app" isn't very descriptive. And then you might have "default_app". So you decide to go and rename it. But it's not so easy with Django.
If you want to rename Django app you need to go through a couple of stages. Final stage might not be neccessary if you're lucky enough.
1. Rename app directory.
2. Change name in your code.
3. Run DB migrations.
4. Migrate tables manually.

Directory level

This one is very easy. You just go and rename a directory. Nothing will stop from this.

Code search & replace

After you renamed your directory, next step would be to go and update your references in code. If you're using IDE it probably has an LSP based "search & replace". If you're like me using neovim, then I'd suggest to use combination of Telescope Grep and quickfix list.
Make sure that all your references in settings.py are properly updated. Also make sure to rename your Config class name. Overall it should be pretty straightforward.

Migrations

After you've updated all your code references, time to migrate database entries. You've already made some migration before, please make sure that in the "migrations" directories you've updated references to your app as well.
Then call

python manage.py makemigrations
python manage.py migrate

Or if you're running your app in docker

docker exec python manage.py makemigrations
docker exec python manage.py migrate

And now if you're lucky - you should be all done! Easy and painless!

But you're unlucky

After all that's done, you might get different errors. There's a different variety, but one of the most common would be about initial migration. You can solve that issue in 2 ways:
1. Flush database. Start from scratch.
2. Manually update entries.

I'll assume that you don't want to clear your database, so let's go and modify entries manually. I will give intrsuctions with the idea that your app runs in docker image, since this is where it might be a little bit trickier to get to DB. And I'm mainly using Postgres.

Access the PostgreSQL container

Open your terminal and run the following command to access the PostgreSQL container. Replace yourservicename with the name of your PostgreSQL service defined in your docker-compose.yml file.

docker-compose exec your_service_name bash

Connect to the PostgreSQL database

Once inside the container, connect to the PostgreSQL database using the psql command. Replace yourdatabasename and yourusername with your actual database name and username.

psql -U your_username -d your_database_name

Run the SQL query

After connecting to the database, you can run your SQL query.

UPDATE django_content_type SET app_label='new_name' WHERE app_label='old_name';

This one should do the trick. But if doesn't, it means that you might need to update all the tables by hand. It will depend on an error.

Inconsistent history error

If you get errordjango.db.migrations.exceptions.InconsistentMigrationHistory then it means that your app is being referenced during migration_001 and there're might some sort of recursive dependency. Doing fake migration might do the trick.
You can fake the initial migration for the articles app to ensure that Django considers it as already applied. Run the following command:

python manage.py migrate new_app_name 0001_initial --fake

If fake migration didn't work.

If fake migration didn't work, then let's try to delete the migration files in the migrations directories of the affected apps. Make sure to keep the init.py file.
Connect to your PostgreSQL database and delete the migration records for the affected apps:

DELETE FROM django_migrations WHERE app='affect_app_name';

After that, make migrations and apply them again. This should start you from scratch.

Updating all the tables

In case you're still struggling - you probably need to update all the tables. Here're queries that you need.
Update django_migrations table

UPDATE django_migrations SET app = 'new_name' WHERE app = 'old_name';

Update django_content_type table

UPDATE django_content_type SET app_label = 'new_name' WHERE app_label = 'old_name';

Update auth_permission table

UPDATE auth_permission SET content_type_id = (SELECT id FROM django_content_type WHERE app_label = 'new_name' AND model = 'your_model_name') 
WHERE content_type_id = (SELECT id FROM django_content_type WHERE app_label = 'old_name' AND model = 'your_model_name');

Update any custom tables

UPDATE your_custom_table SET app_label = 'new_name' WHERE app_label = old_name';

Update django_admin_log table

UPDATE django_admin_log SET content_type_id = (SELECT id FROM django_content_type WHERE app_label = 'new_name' AND model = 'your_model_name')
WHERE content_type_id = (SELECT id FROM django_content_type WHERE app_label = 'old_name' AND model = 'your_model_name');

And you want to update your table names.

ALTER TABLE old_table_name RENAME TO new_table_name;

Usefull commands

Access bash of container

docker-compose exec your_service_name bash

Connect to database

psql -U your_username -d your_database_name

List all users

\du

List all databases

After connecting to PostgreSQL, run the following command to list all databases:

\l

Final words

These snippets should get you through most edge cases. It's a bit pain in the ass, but that's we pay for the convenience of Django.