[Fixed]-Best practice when add a new unique field to an existing django model

15👍

Actually, the source or your issue is not the unique constraint by itself but the fact that your field doesn’t allow nulls and has no default value – you’d have the very same error with a non-unique field.

The proper solution here is to allow the field to be null (null=True) and default it to None (which will translate to sql “null”). Since null values are excluded from unique constraints (at least if your db vendor respects SQL standard), this allow you to apply the schema change while still making sure you cannot have a duplicate for non-null values.

Then you may want a data migration to load the known “other_id” values, and eventually a third schema migration to disallow null values for this field – if and only if you know you have filled this field for all records.

11👍

Django has something called Data Migrations where you create a migration file that modifies/remove/add data to your database as you apply your migrations.

In this case you would create 3 different migrations:

  1. Create a migration that allow null values with null=True.
  2. Create a data migration that populate the data.
  3. Create a migration that disallow null values by removing the null=True added in step 1.

As you then run python manage.py migrate it would apply all of the migrations in step 1-3 in the correct order.

Your data migration would look something like this:

from django.db import migrations

def populate_reference(apps, schema_editor):
    MyModel = apps.get_model('yourappname', 'MyModel')
    for obj in MyModel.objects.all():
        obj.other_id = random_id_generator()
        obj.save()

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(populate_reference),
    ]

You can create an empty migration file using the ./manage.py makemigrations --empty yourappname command.

Leave a comment