@@ 76,8 76,16 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
3. copy the data from the old renamed table to the new table
4. delete the "app_model__old" table
"""
+ # Self-referential fields must be recreated rather than copied from
+ # the old model to ensure their remote_field.field_name doesn't refer
+ # to an altered field.
+ def is_self_referential(f):
+ return f.is_relation and f.remote_field.model is model
# Work out the new fields dict / mapping
- body = {f.name: f for f in model._meta.local_concrete_fields}
+ body = {
+ f.name: f.clone() if is_self_referential(f) else f
+ for f in model._meta.local_concrete_fields
+ }
# Since mapping might mix column names and default values,
# its values must be already quoted.
mapping = {f.column: self.quote_name(f.column) for f in model._meta.local_concrete_fields}
@@ 43,3 43,6 @@ Bugfixes
* Fixed a regression with abstract model inheritance and explicit parent links
(:ticket:`26413`).
+
+* Fixed a migrations crash on SQLite when renaming the primary key of a model
+ containing a ``ForeignKey`` to ``'self'`` (:ticket:`26384`).
@@ 177,3 177,8 @@ class UniqueTest(models.Model):
class Meta:
apps = new_apps
unique_together = ["year", "slug"]
+
+
+class Node(models.Model):
+ node_id = models.AutoField(primary_key=True)
+ parent = models.ForeignKey('self', models.CASCADE, null=True, blank=True)
@@ 27,8 27,8 @@ from .fields import (
from .models import (
Author, AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book,
BookForeignObj, BookWeak, BookWithLongName, BookWithO2O, BookWithoutAuthor,
- BookWithSlug, IntegerPK, Note, NoteRename, Tag, TagIndexed, TagM2MTest,
- TagUniqueRename, Thing, UniqueTest, new_apps,
+ BookWithSlug, IntegerPK, Node, Note, NoteRename, Tag, TagIndexed,
+ TagM2MTest, TagUniqueRename, Thing, UniqueTest, new_apps,
)
@@ 1818,3 1818,14 @@ class SchemaTests(TransactionTestCase):
self.get_constraints_for_column(Tag, 'slug'),
['schema_tag_slug_2c418ba3_like', 'schema_tag_slug_key']
)
+
+ def test_alter_pk_with_self_referential_field(self):
+ """
+ Changing the primary key field name of a model with a self-referential
+ foreign key (#26384).
+ """
+ old_field = Node._meta.get_field('node_id')
+ new_field = AutoField(primary_key=True)
+ new_field.set_attributes_from_name('id')
+ with connection.schema_editor() as editor:
+ editor.alter_field(Node, old_field, new_field)