diff options
| author | Simon Charette <charette.s@gmail.com> | 2017-11-24 03:05:56 -0500 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-12-30 14:59:22 -0500 |
| commit | dcdd219ee1e062dc6189f382e0298e0adf5d5ddf (patch) | |
| tree | 7781d6cd4e8ede3dc234a7739cc939248d6a5b25 /django | |
| parent | 2faeb21d2f618d5bfe9f8f6c574730d3f9407b2a (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.py | 18 | ||||
| -rw-r--r-- | django/db/migrations/operations/fields.py | 32 |
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): |
