Django allows you to define custom UniqueConstraints
to specify which combinations of values are allowed in a row, but removing these later can be problematic when some ForeignKey
is involved, at least with MySQL it may throw a Cannot drop index '...': needed in a foreign key constraint
at you.
The example below shows you how to resolve such a situation in 3 small individual migrations:
- We start with an existing UniqueConstraint.
class MyModel(models.Model):
other_model = models.ForeignKey("OtherModel", on_delete=models.CASCADE)
name = models.CharField(Max_length=128)
class Meta:
constraints = (
models.UniqueConstraint(
fields=(
"other_model",
"name",
),
name="unique_other_model_name",
),
)
- Step 1: Tell Django that we don't want an index and constraint on the
ForeignKey
.
class MyModel(models.Model):
other_model = models.ForeignKey(
"OtherModel",
on_delete=models.CASCADE,
db_index=False,
db_constraint=False,
)
name = models.CharField(max_length=128)
class Meta:
constraints = (
models.UniqueConstraint(
fields=(
"other_model",
"name",
),
name="unique_other_model_name",
),
)
$ python manage.py makemigrations
- Step 2: Remove the custom
UniqueConstraint
.
class MyModel(models.Model):
other_model = models.ForeignKey(
"OtherModel",
on_delete=models.CASCADE,
db_index=False,
db_constraint=False,
)
name = models.CharField(Max_length=128)
$ python manage.py makemigrations
- Step 3: Re-introduce the default behaviour of having an index and constraint on the
ForeignKey
.
class MyModel(models.Model):
other_model = models.ForeignKey( "OtherModel", on_delete=models.CASCADE)
name = models.CharField(Max_length=128)
$ python manage.py makemigrations
You'll end up with 3 migration files that can easily be combined into a single one before running this in production, to tidy things up.
Done!