我正在尝试执行以下操作,但无法在文档或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)
我如何处理所有现有的学生,知道对于未来的学生,我会直接在学校表格中询问学校的外键?
答案 0 :(得分:3)
最简单的解决方案是创建自动迁移,这将是这样的(仅列出操作):
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中的空值。
现在您应该通过将AlterField拆分为3个单独的操作(按顺序)来编辑此迁移:RenameField
(将现有的学校字段重命名为例如school_name),AddField
(将ForeignKey添加到学校模型)和RemoveField
(删除旧的,不需要的字段)。
现在,在AddField
和RemoveField
之间插入RunPython
操作,并在该操作中运行将创建新School对象的代码(如果数据库中没有此类对象)并将对象分配给你的Student
。
简单来说:迁移会创建名为School
的新模型,将旧字段school
重命名为school_name
,创建新字段school
(ForeignKey
为模型School
中的Student
},遍历所有学生创建新School
个对象并将其分配给学生,最后一步,删除旧的school_name
字段(以前称为{{1} }})。
您还可以向school
提供反向代码,以便您可以在不丢失数据的情况下撤消迁移。
答案 1 :(得分:0)
如果您想要使用ORM进行实时操作,可以将Student.school
字段重命名为Student.school_old
,然后添加Student.school
ForeignKey,并使用以下代码段进行制作确保数据正常:
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()