﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
34647	Foreign Key index names are not renamed when a model is renamed	Steven Mapes	nobody	"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.

Here's how to create the problem on a fresh project

{{{
from django.db import models
from django.contrib.auth.models import User


class ThisIsAModelWithALongName(models.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)
}}}

{{{ python manage.py makemigrations && python manage.py migrate }}}

Step 2 - Rename the top class and the FK in the 2nd class but leave the related name in the first class

{{{
from django.db import models
from django.contrib.auth.models import User


class ThisIsAModelWithALongNameOld(models.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)
}}}
    
Run migrations
    
Step 3 - Add the new model back, add an FK into the AnotherClassHere table and rename the related_name on the first (old) model
 
{{{    
from django.db import models
from django.contrib.auth.models import User


class ThisIsAModelWithALongNameOld(models.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):
    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)
}}}

run migrations, the error will occur and the DB will be left in a partially migrated state that can't be rolled back"	Bug	new	Migrations	4.2	Normal		migrations, sql, foreign_key,mysql		Unreviewed	0	0	0	0	0	0
