Ver Fonte

Fixed #26384 -- Fixed renaming the PK on a model with a self-referential FK on SQLite.

Alex Hill há 9 anos atrás
pai
commit
4b2cf1cd27

+ 9 - 1
django/db/backends/sqlite3/schema.py

@@ -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}

+ 3 - 0
docs/releases/1.9.5.txt

@@ -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`).

+ 5 - 0
tests/schema/models.py

@@ -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)

+ 13 - 2
tests/schema/tests.py

@@ -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,
 )
 
 
@@ -1819,3 +1819,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)