Django new ForeignKey field based on existing field

I am trying to do the following, but cannot find a good solution in the documentation or on stackoverflow.

I have an existing database with ~ 1000 users with this model:

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 existing students knowing that for future students I will ask the foreignkey school directly in the signature form?

+3


source to share


2 answers


The simplest solution is to create an automatic migration, which 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 edited the Student model so that the ForeignKey can now be null, you can remove the null in the AlterField at the end of the transfer if you are sure everyone Student

will have School

.

You should now edit this migration by splitting the AlterField into 3 separate operations (sequentially): RenameField

(to rename the existing school char, for example school_name), AddField

(to add a ForeignKey to the school model) and RemoveField

(to remove the old, unnecessary char field).



Now insert an RunPython

operation between AddField

and RemoveField

and inside this operation start code, which will create new School objects (if there is no such object in the database) and assign the object to yours Student

.

In simple words: migration will create a new model named School

, rename the old field School

to school_name

, create a new field School

( ForeignKey

to School

) in the model Student

, iterate over all students creating new objects School

and assigning them to students, and in the last step, delete the old field school_name

(previously called School

).

You can also provide the reverse code in RunPython

so that you can undo this migration without losing data.

+2


source


If you want to do it live using an ORM, you can rename the field Student.school

to Student.school_old

and then add a Student.school

ForeignKey and use the following snippet to make sure the data is in order:



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()

      

0


source







All Articles