Testing Django Migrations with PostgreSQL and Foreign Keys

2025-10-01

The incredibly helpful blogpost Writing Unit Tests for Django Migrations delivers what the title promises. Making testing of migrations.RunPython feasible and easy … as long as you don’t have to fill foreign key relations on PostgreSQL.

Following the suggested approach, you’ll create records to be migrated in the setUpBeforeMigration method.

class TestLeadSourceMigration(TestMigrations):
    migrate_from = "0056_rename_creator_leadsource_created_by_user"
    migrate_to = "0057_leadsource_channel_and_more"

    def setUpBeforeMigration(self, apps):
        Lead = apps.get_model("leadtool", "Lead")
        LeadSource = apps.get_model("leadtool", "LeadSource")

        lead = Lead.objects.create(
            identifier=1,
            first_name="Jane",
            last_name="Doe",
            email="jane.doe@example.com",
        )
        LeadSource.objects.create(lead=lead)

    def test_something(self):
        [...]

Running this test will not succeed.

django.db.utils.OperationalError: cannot ALTER TABLE "leadtool_leadsource" because it has pending trigger events

The suggested TestMigrations class is a subclass of TestCase, which executes each test method and associated lifecycle methods like setUp, and by extension setUpBeforeMigration, in a single transaction. The pending foreign key trigger events, prevent the ALTER TABLE and any other DDL of the succeeding migration to run.

We have a trivial fix though: inherit from TransactionTestCase. Now the record creation is committed to the database. Note that the database is reset to a known state by truncating all database tables instead of just rolling back a transaction, which is slower. Well worth it, though!

PS: Could we please take a moment to appreciate how well the wisdom of that 9.5 year old post held up?