summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2017-11-24 03:05:56 -0500
committerTim Graham <timograham@gmail.com>2017-12-30 14:59:22 -0500
commitdcdd219ee1e062dc6189f382e0298e0adf5d5ddf (patch)
tree7781d6cd4e8ede3dc234a7739cc939248d6a5b25 /django
parent2faeb21d2f618d5bfe9f8f6c574730d3f9407b2a (diff)
Fixed #25817 -- Made RenameField repoint to_field/to_fields references.
Also updated the autodetector to assume the RenameField operation will perform the required repointing.
Diffstat (limited to 'django')
-rw-r--r--django/db/migrations/autodetector.py18
-rw-r--r--django/db/migrations/operations/fields.py32
2 files changed, 47 insertions, 3 deletions
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index 1dce17be6e..0ccb726b3d 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -895,6 +895,24 @@ class MigrationAutodetector:
)
if rename_key in self.renamed_models:
new_field.remote_field.model = old_field.remote_field.model
+ # Handle ForeignKey which can only have a single to_field.
+ remote_field_name = getattr(new_field.remote_field, 'field_name', None)
+ if remote_field_name:
+ to_field_rename_key = rename_key + (remote_field_name,)
+ if to_field_rename_key in self.renamed_fields:
+ new_field.remote_field.field_name = old_field.remote_field.field_name
+ # Handle ForeignObjects which can have multiple from_fields/to_fields.
+ from_fields = getattr(new_field, 'from_fields', None)
+ if from_fields:
+ from_rename_key = (app_label, model_name)
+ new_field.from_fields = tuple([
+ self.renamed_fields.get(from_rename_key + (from_field,), from_field)
+ for from_field in from_fields
+ ])
+ new_field.to_fields = tuple([
+ self.renamed_fields.get(rename_key + (to_field,), to_field)
+ for to_field in new_field.to_fields
+ ])
if hasattr(new_field, "remote_field") and getattr(new_field.remote_field, "through", None):
rename_key = (
new_field.remote_field.through._meta.app_label,
diff --git a/django/db/migrations/operations/fields.py b/django/db/migrations/operations/fields.py
index d103e5c127..96b0045744 100644
--- a/django/db/migrations/operations/fields.py
+++ b/django/db/migrations/operations/fields.py
@@ -270,8 +270,9 @@ class RenameField(FieldOperation):
model_state = state.models[app_label, self.model_name_lower]
# Rename the field
fields = model_state.fields
+ found = False
for index, (name, field) in enumerate(fields):
- if name == self.old_name:
+ if not found and name == self.old_name:
fields[index] = (self.new_name, field)
# Delay rendering of relationships if it's not a relational
# field and not referenced by a foreign key.
@@ -279,8 +280,15 @@ class RenameField(FieldOperation):
not field.is_relation and
not is_referenced_by_foreign_key(state, self.model_name_lower, field, self.name)
)
- break
- else:
+ found = True
+ # Fix from_fields to refer to the new field.
+ from_fields = getattr(field, 'from_fields', None)
+ if from_fields:
+ field.from_fields = tuple([
+ self.new_name if from_field_name == self.old_name else from_field_name
+ for from_field_name in from_fields
+ ])
+ if not found:
raise FieldDoesNotExist(
"%s.%s has no field named '%s'" % (app_label, self.model_name, self.old_name)
)
@@ -292,6 +300,24 @@ class RenameField(FieldOperation):
[self.new_name if n == self.old_name else n for n in together]
for together in options[option]
]
+ # Fix to_fields to refer to the new field.
+ model_tuple = app_label, self.model_name_lower
+ for (model_app_label, model_name), model_state in state.models.items():
+ for index, (name, field) in enumerate(model_state.fields):
+ remote_field = field.remote_field
+ if remote_field:
+ remote_model_tuple = self._get_model_tuple(
+ remote_field.model, model_app_label, model_name
+ )
+ if remote_model_tuple == model_tuple:
+ if getattr(remote_field, 'field_name', None) == self.old_name:
+ remote_field.field_name = self.new_name
+ to_fields = getattr(field, 'to_fields', None)
+ if to_fields:
+ field.to_fields = tuple([
+ self.new_name if to_field_name == self.old_name else to_field_name
+ for to_field_name in to_fields
+ ])
state.reload_model(app_label, self.model_name_lower, delay=delay)
def database_forwards(self, app_label, schema_editor, from_state, to_state):