Step-by-step workflow for making Django model changes and creating/applying database migrations in the Lotus project. Use this skill whenever the user wants to add a field, create a new model, modify an existing model, add seed data, or run makemigrations/migrate commands. Also trigger for questions about the migration state, rolling back migrations, or anything touching services/django/core/models.py or services/django/core/migrations/.
Django service: services/django/
Models: services/django/core/models.py
Migrations: services/django/core/migrations/
Docker service name: django_admin
Open services/django/core/models.py and make the desired changes:
models.ModelRead the file first to understand existing patterns (UUID PKs, db_table, db_column conventions) before making changes.
The django_admin container must be up and postgres must be healthy before running migrations.
If services aren't running:
make up
If you want to check without starting everything:
docker compose -f docker/docker-compose-local.yaml ps django_admin postgres
The
django_adminservice has a volume mount (services/django:/app), so edits to local files are immediately reflected in the container — no rebuild needed.
docker compose -f docker/docker-compose-local.yaml exec django_admin python manage.py makemigrations
This creates a new file in services/django/core/migrations/ following the pattern 000N_description.py.
After it runs, read the generated file and verify:
dependencies list chains correctly to the previous migrationTo give the migration a descriptive name instead of auto-generated:
docker compose -f docker/docker-compose-local.yaml exec django_admin python manage.py makemigrations --name describe_your_change
docker compose -f docker/docker-compose-local.yaml exec django_admin python manage.py migrate
Watch for errors. Common issues:
showmigrationsdocker compose -f docker/docker-compose-local.yaml exec django_admin python manage.py showmigrations
All migrations should show [X]. If any show [ ], run migrate again.
When a migration needs to insert data (not just schema changes), use migrations.RunSQL() with both forward and reverse SQL so rollbacks work:
migrations.RunSQL(
sql="INSERT INTO source.my_table (id, name) VALUES (gen_random_uuid(), 'example');",
reverse_sql="DELETE FROM source.my_table WHERE name = 'example';",
),
The database search_path is set to source,public, so models map to the source schema. Use explicit source.table_name in raw SQL to be unambiguous.
To revert to a previous migration state, pass the target migration number:
docker compose -f docker/docker-compose-local.yaml exec django_admin python manage.py migrate core 000N
Where 000N is the migration you want to end up at (not the one you're undoing). Django will run the reverse operations of all migrations after that point.
dependencies — the order matters and must be kept linear within the core app.entrypoint.sh runs migrate automatically on container start, so the migration will also apply on the next make up / container restart.