Reputation: 1522
Django migration can detect if a field was renamed and ask you about it (instead of the old fashion delete/create) Even if multiple fields are changed it seems to find the corresponding match. For example:
Before:
class DirectoryMirror(models.Model):
directory_origin = models.ForeignKey(TapeDirectory)
machine_target = models.ForeignKey(GenericMachine)
directory_target = models.CharField(max_length=255, blank=False)
After (changing field names):
class DirectoryMirror(models.Model):
source_directory = models.ForeignKey(TapeDirectory)
target_machine = models.ForeignKey(GenericMachine)
target_directory = models.CharField(max_length=255, blank=False)
Generating migration:
$ ./manage.py makemigrations
Did you rename directorymirror.directory_origin to directorymirror.source_directory (a ForeignKey)? [y/N] y
Did you rename directorymirror.directory_target to directorymirror.target_directory (a CharField)? [y/N] y
Did you rename directorymirror.machine_target to directorymirror.target_machine (a ForeignKey)? [y/N] y
How does it manage to detect the renaming and find the correct match?
Upvotes: 1
Views: 550
Reputation: 7197
Here it is the algorithm https://github.com/django/django/blob/bc77eb6d0858652e197c08c299efaeb06c51efee/django/db/migrations/autodetector.py#L757
Copying it here
def generate_renamed_fields(self): """ Works out renamed fields """ self.renamed_fields = {} for app_label, model_name, field_name in sorted(self.new_field_keys - self.old_field_keys): old_model_name = self.renamed_models.get((app_label, model_name), model_name) old_model_state = self.from_state.models[app_label, old_model_name] field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name) # Scan to see if this is actually a rename! field_dec = self.deep_deconstruct(field) for rem_app_label, rem_model_name, rem_field_name in sorted(self.old_field_keys - self.new_field_keys): if rem_app_label == app_label and rem_model_name == model_name: old_field_dec = self.deep_deconstruct(old_model_state.get_field_by_name(rem_field_name)) if field.remote_field and field.remote_field.model and 'to' in old_field_dec[2]: old_rel_to = old_field_dec[2]['to'] if old_rel_to in self.renamed_models_rel: old_field_dec[2]['to'] = self.renamed_models_rel[old_rel_to] if old_field_dec == field_dec: if self.questioner.ask_rename(model_name, rem_field_name, field_name, field): self.add_operation( app_label, operations.RenameField( model_name=model_name, old_name=rem_field_name, new_name=field_name, ) ) self.old_field_keys.remove((rem_app_label, rem_model_name, rem_field_name)) self.old_field_keys.add((app_label, model_name, field_name)) self.renamed_fields[app_label, model_name, field_name] = rem_field_name break
Upvotes: 2