The likely cause of this is rooted in your model having check constraints on it via the Meta.constraints
option. Check constraints (in Postgres) are implemented as triggers that execute at the end of a transaction. By default, a Django migration file encloses all migrations operations from a file in a single transaction. This means that other ALTER TABLE
operations may happen before your triggers fire, a situation that Postgres can't handle.
In order to get around this issue, you can do like another answer suggested:
operations = [
migrations.RemoveField(...). # Do your normal table operations
migrations.RunPython(migration_func),
# Evaluate the check constraints
migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
migrations.RemoveField(...). # Run the rest of your table operations
]
Running 'SET CONSTRAINTS ALL IMMEDIATE;'
after the data migration ensures that all of those check constraints that normally wait until the end of the transaction will fire, meaning there are no more pending trigger events before the next ALTER TABLE
statements.
FYI - This setting is effective for only the Django migration runner in that transaction. It won't affect other database sessions or any subsequent migration files.
Unlike the other answer linked, I'd avoid running an additional migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;')
, otherwise you may alter the behavior of other triggers in subsequent steps that should run immediately (i.e. application triggers that track history, etc, that aren't check constraints).
Just wanted to add some more clarity here on exactly why this is happening since this is an older question with many different answers.