Fixed #28350 -- Fixed UnboundLocalError crash in RenameField with nonexistent field.
Thanks Tim for the review.
This commit is contained in:
parent
b9f7dce84b
commit
5cbcb36839
|
@ -1,3 +1,4 @@
|
||||||
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db.models.fields import NOT_PROVIDED
|
from django.db.models.fields import NOT_PROVIDED
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
@ -261,25 +262,27 @@ class RenameField(FieldOperation):
|
||||||
)
|
)
|
||||||
|
|
||||||
def state_forwards(self, app_label, state):
|
def state_forwards(self, app_label, state):
|
||||||
|
model_state = state.models[app_label, self.model_name_lower]
|
||||||
# Rename the field
|
# Rename the field
|
||||||
state.models[app_label, self.model_name_lower].fields = [
|
fields = model_state.fields
|
||||||
(self.new_name if n == self.old_name else n, f)
|
for index, (name, field) in enumerate(fields):
|
||||||
for n, f in state.models[app_label, self.model_name_lower].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
|
# 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'):
|
for option in ('index_together', 'unique_together'):
|
||||||
if option in options:
|
if option in options:
|
||||||
options[option] = [
|
options[option] = [
|
||||||
[self.new_name if n == self.old_name else n for n in together]
|
[self.new_name if n == self.old_name else n for n in together]
|
||||||
for together in options[option]
|
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)
|
state.reload_model(app_label, self.model_name_lower, delay=delay)
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
|
|
|
@ -54,3 +54,6 @@ Bugfixes
|
||||||
|
|
||||||
* Prevented a primary key alteration from adding a foreign key constraint if
|
* Prevented a primary key alteration from adding a foreign key constraint if
|
||||||
``db_constraint=False`` (:ticket:`28298`).
|
``db_constraint=False`` (:ticket:`28298`).
|
||||||
|
|
||||||
|
* Fixed ``UnboundLocalError`` crash in ``RenameField`` with nonexistent field
|
||||||
|
(:ticket:`28350`).
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db import connection, migrations, models, transaction
|
from django.db import connection, migrations, models, transaction
|
||||||
from django.db.migrations.migration import Migration
|
from django.db.migrations.migration import Migration
|
||||||
from django.db.migrations.operations import CreateModel
|
from django.db.migrations.operations import CreateModel
|
||||||
|
@ -1368,6 +1369,12 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertEqual(definition[1], [])
|
self.assertEqual(definition[1], [])
|
||||||
self.assertEqual(definition[2], {'model_name': "Pony", 'old_name': "pink", 'new_name': "blue"})
|
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):
|
def test_alter_unique_together(self):
|
||||||
"""
|
"""
|
||||||
Tests the AlterUniqueTogether operation.
|
Tests the AlterUniqueTogether operation.
|
||||||
|
|
Loading…
Reference in New Issue