【问题标题】:Django new ForeignKey field based on existing fieldDjango 基于现有字段的新 ForeignKey 字段
【发布时间】:2015-11-02 01:15:40
【问题描述】:

我正在尝试执行以下操作,但在文档或 stackoverflow 上找不到好的解决方案。

我有一个现有的数据库,有大约 1000 个用户使用这个模型:

class Student(AbstractBaseUser):
    email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
    school = models.CharField(max_length=255,null=True, blank=True)
    ...

但我最终决定使用单独的模型来处理学校:

class Student(AbstractBaseUser):
    email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
    school = models.ForeignKey('School')

class School(models.Model):
    name = models.CharField(max_length=255,unique=True)

明知道以后的学生会在订阅表中直接询问学校外键,我该如何处理所有现有的学生?

【问题讨论】:

    标签: python django model foreign-keys default


    【解决方案1】:

    如果您想实时使用 ORM,您可以将 Student.school 字段重命名为 Student.school_old,然后添加 Student.school ForeignKey,并使用以下 sn-p 确保数据是好的:

    for student in Student.objects.filter(school__isnull=False):
        try:
            school = School.objects.get(name=student.school_old)
        except School.DoesNotExist:
            school = School.objects.create(name=student.school_old)
        student.school = school
        student.save()
    

    【讨论】:

    • 我不确定这是否是“正确”的方式,因为我们现在有迁移。不过,这将是一个简单快捷的解决方案。
    • Django 中有一个get_or_create 函数。您的 try-except 已过时。加上 objects.create() 保存对象。
    【解决方案2】:

    最简单的解决方案是创建自动迁移,这将是这样的(仅列出操作):

        operations = [
            migrations.CreateModel(
                name='School',
                fields=[
                    ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                    ('name', models.CharField(unique=True, max_length=255)),
                ],
            ),
            migrations.AlterField(
                model_name='Student',
                name='school',
                field=models.ForeignKey(blank=True, to='testapp.School', null=True),
            ),
        ]
    

    我已经编辑了模型 Student,所以现在 ForeignKey 可以为 null,如果您确定每个 Student 都会分配有 School,则可以在迁移结束时删除 AlterField 中的 null 值。

    现在您应该通过将 AlterField 拆分为 3 个单独的操作(按顺序)来编辑此迁移:RenameField(将现有的学校字符字段重命名为例如 school_name)、AddField(将 ForeignKey 添加到学校模型)和 @ 987654323@(删除旧的、不需要的字符字段)。

    现在,在AddFieldRemoveField 之间插入RunPython 操作,并在该操作中运行代码,该代码将创建新的学校对象(如果数据库中没有此类对象)并将对象分配给您的Student

    简单来说:迁移将创建新模型,命名为School,将旧字段school 重命名为school_name,在模型Student 中创建新字段schoolForeignKeySchool),遍历所有学生创建新的School 对象并将其分配给学生,然后在最后一步删除旧的school_name 字段(以前称为school)。

    您还可以在RunPython 中提供反向代码,这样您就可以在不丢失数据的情况下反向迁移。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 2018-03-01
      • 2020-08-02
      • 1970-01-01
      • 2014-12-25
      • 1970-01-01
      • 2012-10-18
      相关资源
      最近更新 更多