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

If you’re here, it means you’ve come across this problem too.

django.db.utils.OperationalError: cannot ALTER TABLE “X” because it has pending trigger events

What’s the issue?

I wanted to remove null=True from a few fields.

According to Django docs:

Avoid using null on string-based fields such as CharField and TextField. If a string-based field has null=True, that means it has two possible values for “no data”: NULL, and the empty string. In most cases, it’s redundant to have two possible values for “no data;” the Django convention is to use the empty string, not NULL. One exception is when a CharField has both unique=True and blank=True set. In this situation, null=True is required to avoid unique constraint violations when saving multiple objects with blank values.

I removed the null=True from CharField. Django generated this migration:

migrations.AlterField(
model_name="user",
name="first_name",
field=models.CharField(
blank=True, default="", max_length=30, verbose_name="first name"
),
preserve_default=False,
),

The database already contained users with first_name set to null and because of that, the migration raised the error mentioned above.

Solution? I’ve created additional migration to convert null values to an empty string (''). I put this migration before the migration where I want to remove null=True.

To create an empty migration, use --empty param.

Terminal window
python manage.py makemigrations users --empty

The migration.

from django.db import migrations
def postgres_migration_prep(apps, schema_editor):
User = apps.get_model("users", "User")
fields = ("first_name", "last_name", "city")
for field in fields:
filter_param = {"{}__isnull".format(field): True}
update_param = {field: ""}
User.objects.filter(**filter_param).update(**update_param)
class Migration(migrations.Migration):
dependencies = [("users", "0002_auto_20190710_1101")]
operations = [
migrations.RunPython(postgres_migration_prep, migrations.RunPython.noop)
]

This migration does not contain reverse code which is required for unapplying migrations. I didn’t need it.