Search code examples
djangopython-3.xuniquedjango-orm

Django add unique constraint only for new records


I have a django model:

from django.db import models

class TestModel(models.Model):
  name = models.CharField("Name", null=False, blank=False, max_length=300)

After some time I got a task to add a unique constraint such that my new model looks like this:

from django.db import models

class Test(models.Model):
  name = models.CharField("Title", null=False, blank=False, max_length=300, unique=True)

After this I need to do makemigrations and migrate. However in my DB I already have records with duplicate names.

My question: I want to apply constraint only for the new records. Is there a way to do so? (allow old duplicates to remain in the DB but prevent new ones to be created).

At the moment I am getting IntegrityError on my old records while migrate.


Solution

  • No there is no way to do that, because a database-level constraint needs to be fulfilled for the entire table.

    You can either:

    • Migrate your old data first to make your field unique (e.g. appending random strings/numbers at the end of the duplicate names)
    • Or not add the constraint at the database level but by adding a custom validator to your field that will only be checked by Django at validation time.
    • Or by checking this at saving time (e.g. by overriding the model's save() method).

    These last two methods have the disadvantage that you cannot guarantee that no new duplicate records will be added, e.g. via bulk adding or someone adding code in the future forgetting to validate.

    Note that this will also mean that existing records will not validate when trying to change them.

    A final alternative is to create a new field with blank=False, null=True, default=None, unique=True that you make None for the existing rows. If None, you show the existing name field (legacy), otherwise the new name field.