简体   繁体   English

Django新的ForeignKey字段基于现有字段

[英]Django new ForeignKey field based on existing field

I am trying to do the following but can't find a good solution on the documentation or on stackoverflow. 我试图执行以下操作,但无法在文档或stackoverflow上找到一个好的解决方案。

I have an existing database with ~1000 users with this model: 我有一个现有的数据库,有大约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)
    ...

But I finally decided to use a separate model to handle schools : 但我最终决定使用一个单独的模型来处理学校:

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)

How can I handle all the existing students, knowing that for the future students, I will be asking the school foreignkey directly in the suscription form ? 我如何处理所有现有的学生,知道对于未来的学生,我会直接在学校表格中询问学校的外键?

Simplest solution wolud be to create auto migration, that will be something like this (listing only operations): 最简单的解决方案是创建自动迁移,这将是这样的(仅列出操作):

    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),
        ),
    ]

I've edited model Student, so now ForeignKey can be null, you can remove null value in AlterField on the end of migration if you're sure that every Student will have School assigned. 我已经编辑了模型学生,所以现在ForeignKey可以为null,如果你确定每个Student都有School分配,你可以在迁移结束时删除AlterField中的空值。

Now you should edit this migration by splitting AlterField into 3 separate operations (in sequence): RenameField (to rename existing school char field to for example school_name), AddField (to add ForeignKey to school model) and RemoveField (to remove old, unneeded char field). 现在,你应该修改通过拆分AlterField这种迁移到3个独立的操作(按顺序): RenameField (重新命名学校现有的焦炭领域例如school_name), AddField (添加ForeignKey的学校模型)和RemoveField (删除不需要的旧炭领域)。

Now, insert RunPython operation between AddField and RemoveField and inside that operation run code that will create new School objects (if there is no such object in database) and assign object to your Student . 现在,在AddFieldRemoveField之间插入RunPython操作,并在该操作中运行将创建新School对象的代码(如果数据库中没有这样的对象)并将对象分配给您的Student

In simple words: migration will create new model, named School , rename old field school to school_name , create new field school ( ForeignKey to School ) in model Student , iterate through all studens creating new School objects and assigning it into students and on last step, remove old school_name field (previously named school ). 简单来说:迁移将创建名为School新模型,将旧的field school重命名为school_name ,在模型Student创建新的field schoolForeignKey to School ),遍历所有学生创建新的School对象并将其分配给学生并在最后一步,删除旧的school_name字段(以前命名为school )。

You can also provide reverse code into RunPython so you can reverse that migration without data loss. 您还可以向RunPython提供反向代码,以便您可以在不丢失数据的情况下撤消迁移。

If you would want to do it live, using the ORM, you could rename the Student.school field to Student.school_old , then add the Student.school ForeignKey, and use the following snippet to make sure the data is ok: 如果您想要使用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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM