summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2017-06-30 08:35:58 -0400
committerSimon Charette <charette.s@gmail.com>2017-06-30 13:12:33 -0400
commitc1621d80089cb3e77c8a504310feeb24fea61afe (patch)
tree35d0cbcf6070be1af5e1c1a7b3eea29b133fb2a1
parenta6756195c1a11eee10c16c96fe95d52e22e1d9ba (diff)
[1.11.x] Fixed #28350 -- Fixed UnboundLocalError crash in RenameField with nonexistent field.
Thanks Tim for the review. Backport of 5cbcb3683964205ce023157ca181d05a31be2ab5 from master
-rw-r--r--django/db/migrations/operations/fields.py25
-rw-r--r--docs/releases/1.11.3.txt3
-rw-r--r--tests/migrations/test_operations.py7
3 files changed, 24 insertions, 11 deletions
diff --git a/django/db/migrations/operations/fields.py b/django/db/migrations/operations/fields.py
index 4ce465a0c3..a458397fd4 100644
--- a/django/db/migrations/operations/fields.py
+++ b/django/db/migrations/operations/fields.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+from django.core.exceptions import FieldDoesNotExist
from django.db.models.fields import NOT_PROVIDED
from django.utils.functional import cached_property
@@ -268,25 +269,27 @@ class RenameField(FieldOperation):
)
def state_forwards(self, app_label, state):
+ model_state = state.models[app_label, self.model_name_lower]
# Rename the field
- state.models[app_label, self.model_name_lower].fields = [
- (self.new_name if n == self.old_name else n, f)
- for n, f in state.models[app_label, self.model_name_lower].fields
- ]
+ fields = model_state.fields
+ for index, (name, field) in enumerate(fields):
+ if name == self.old_name:
+ fields[index] = (self.new_name, field)
+ # Delay rendering of relationships if it's not a relational field.
+ delay = not field.is_relation
+ break
+ else:
+ raise FieldDoesNotExist(
+ "%s.%s has no field named '%s'" % (app_label, self.model_name, self.old_name)
+ )
# Fix index/unique_together to refer to the new field
- options = state.models[app_label, self.model_name_lower].options
+ options = model_state.options
for option in ('index_together', 'unique_together'):
if option in options:
options[option] = [
[self.new_name if n == self.old_name else n for n in together]
for together in options[option]
]
- for n, f in state.models[app_label, self.model_name_lower].fields:
- if n == self.new_name:
- field = f
- break
- # Delay rendering of relationships if it's not a relational field
- delay = not field.is_relation
state.reload_model(app_label, self.model_name_lower, delay=delay)
def database_forwards(self, app_label, schema_editor, from_state, to_state):
diff --git a/docs/releases/1.11.3.txt b/docs/releases/1.11.3.txt
index 1c716bf5a3..227c94abb4 100644
--- a/docs/releases/1.11.3.txt
+++ b/docs/releases/1.11.3.txt
@@ -54,3 +54,6 @@ Bugfixes
* Prevented a primary key alteration from adding a foreign key constraint if
``db_constraint=False`` (:ticket:`28298`).
+
+* Fixed ``UnboundLocalError`` crash in ``RenameField`` with nonexistent field
+ (:ticket:`28350`).
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index 3b2bd8275c..64ae395d94 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import unittest
+from django.core.exceptions import FieldDoesNotExist
from django.db import connection, migrations, models, transaction
from django.db.migrations.migration import Migration
from django.db.migrations.operations import CreateModel
@@ -1370,6 +1371,12 @@ class OperationTests(OperationTestBase):
self.assertEqual(definition[1], [])
self.assertEqual(definition[2], {'model_name': "Pony", 'old_name': "pink", 'new_name': "blue"})
+ def test_rename_missing_field(self):
+ state = ProjectState()
+ state.add_model(ModelState('app', 'model', []))
+ with self.assertRaisesMessage(FieldDoesNotExist, "app.model has no field named 'field'"):
+ migrations.RenameField('model', 'field', 'new_field').state_forwards('app', state)
+
def test_alter_unique_together(self):
"""
Tests the AlterUniqueTogether operation.