字段重命名如何在django迁移中起作用?

时间:2015-06-22 12:04:31

标签: django-models django-migrations

Django迁移可以检测字段是否已重命名并询问您(而不是旧方式删除/创建) 即使多个字段被更改,它似乎找到相应的匹配。例如:

在:

class DirectoryMirror(models.Model):
    directory_origin = models.ForeignKey(TapeDirectory)
    machine_target = models.ForeignKey(GenericMachine)
    directory_target = models.CharField(max_length=255, blank=False) 

之后(更改字段名称):

class DirectoryMirror(models.Model):
    source_directory = models.ForeignKey(TapeDirectory)
    target_machine = models.ForeignKey(GenericMachine)
    target_directory = models.CharField(max_length=255, blank=False)

生成迁移:

$ ./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

如何设法检测重命名并找到正确的匹配?

1 个答案:

答案 0 :(得分:2)

这是算法https://github.com/django/django/blob/bc77eb6d0858652e197c08c299efaeb06c51efee/django/db/migrations/autodetector.py#L757

在此处复制

    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