How to add unique field to existing Django model - a1k89/Blog GitHub Wiki

Prepare

  • For example, you have existing Django User model
  • You want to add new unique field. For example, referal_code
  • If simple add unique field and run migrate command - you got error (because some instances already exist)

Variants

  1. Add None to field. Make migrations. Fill existing rows unique values and then add unique=True. Make migrations again
  2. Via migrations.

Solution

I choose variant number 2.

  1. Add field to model
referal_code = models.CharField(editable=False,
                                default=referal_code_generator,
                                unique=True,
                                max_length=100)
  1. Run makemigrations
  2. Then, generate two empty migrations
makemigrations myapp --empty twice
  1. In a first migration change unique to null:
...
operations = [
        migrations.AddField(
            model_name='user',
            name='referal_code',
            field=models.CharField(default=apps.user.utils.referal_code_generator, editable=False,
                                   max_length=100,
                                   null=True),
        ),
    ]
  1. To the last migration please add (copy original code from first migration):
  migrations.AlterField(
            model_name='user',
            name='referal_code',
            field=models.CharField(default=apps.user.utils.referal_code_generator, editable=False,
                                   max_length=100,
                                   unique=True),
        ),
  1. And finally, change second migration to:
def gen_referal_code(apps, schema_editor):
    User = apps.get_model('user', 'User')
    for row in User.objects.all():
        row.referal_code = utils.referal_code_generator()
        row.save(update_fields=['referal_code'])

class Migration(migrations.Migration):

    ....

    operations = [
        migrations.RunPython(gen_referal_code, reverse_code=migrations.RunPython.noop)
    ]
  1. Run migrate.

After that our actions will be:

  1. The first migration add null values to referal_code
  2. The second migration fill existing rows unique values
  3. The last migration add unique=True to our field.

Thanks for reading