Opened 19 months ago
Last modified 19 months ago
#34647 closed Bug
Foreign Key index names are not renamed when a model is renamed — at Initial Version
Reported by: | Steven Mapes | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | 4.2 |
Severity: | Normal | Keywords: | migrations, sql, foreign_key, mysql |
Cc: | Bhuvnesh, Simon Charette, Mariusz Felisiak, David, Wobrock | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I encountered an issue yesterday where Django created a foreign key that already exists.
The way I encountered this was to take a model called CriticalPathTemplate
with a property called archived_by
which is a foreign key to the user table, then renamed the model to CriticalPathTemplateOld
and ran migrations. This renamed the table but left the indexes as they were.
I then added a new model called CriticalPathTemplate
(business requirement) and ran makemigrations and migrate. The migrations were made but makemigrations failed due to a foreign key name clash. I ended up renaming the column but then hit further issues for the next FK in the table E.G {{{django.db.utils.OperationalError: (1826, "Duplicate foreign key constraint name 'critical_path_templa_origin_agent_shortco_f9715e87_fk_address_s'")
}}}
Looking at the output of sqlmigrate for the new migration and comparing the name of the foreign keys that Django generated I can see several that are going to clash as the indexes on the old table were not renamed when the table was renamed by the migration.
I did manage to re-create the issue this morning on both SQL Lite and MySQL backends on a new project, but having sat down to create the bug report I am now struggling to have Django invoking migrations.RenameModel as it's just dropping and then creating the models, with all data, instead.
I will have another go at the test project but it simply had two models
from django.db import models from django.contrib.auth.models import User class ThisIsAModelWithALongName(models.Model): """The Original Model""" name = models.CharField(max_length=128, blank=True) archived_by = models.ForeignKey(User, null=True, blank=True, default=None, related_name="model_with_log_names", on_delete=models.SET_NULL) class AnotherClassHere(models.Model): long_name_property = models.ForeignKey(ThisIsAModelWithALongName, null=True, blank=True, default=None, related_name="another_class_here", on_delete=models.SET_NULL)
I then renamed the model
from django.db import models from django.contrib.auth.models import User class ThisIsAModelWithALongNameOld(models.Model): """The Original Model""" name = models.CharField(max_length=128, blank=True) archived_by = models.ForeignKey(User, null=True, blank=True, default=None, related_name="model_with_log_names_old", on_delete=models.SET_NULL) class AnotherClassHere(models.Model): long_name_property_old = models.ForeignKey(ThisIsAModelWithALongNameOld, null=True, blank=True, default=None, related_name="another_class_here", on_delete=models.SET_NULL)
Then I created the new model with the same name as the old model
from django.db import models from django.contrib.auth.models import User class ThisIsAModelWithALongNameOld(models.Model): """The Original Model""" name = models.CharField(max_length=128, blank=True) archived_by = models.ForeignKey(User, null=True, blank=True, default=None, related_name="model_with_log_names_old", on_delete=models.SET_NULL) class ThisIsAModelWithALongName(models.Model): """The NEW Model""" name = models.CharField(max_length=128, blank=True) archived_by = models.ForeignKey(User, null=True, blank=True, default=None, related_name="model_with_log_names", on_delete=models.SET_NULL) class AnotherClassHere(models.Model): long_name_property_old = models.ForeignKey(ThisIsAModelWithALongNameOld, null=True, blank=True, default=None, related_name="another_class_here", on_delete=models.SET_NULL) long_name_property = models.ForeignKey(ThisIsAModelWithALongName, null=True, blank=True, default=None, related_name="another_class_here", on_delete=models.SET_NULL)
MySQL version was 8.0.33 using mysqlclient==2.1.1