我在一个项目中工作,有多个字段使用through
相关模型创建为M2M,但当时创建错误,相关模型没有额外的字段,所以我想使用Django管理的常规M2M。
我现有的型号有:
cass Student(models.Model):
# ... other fields..."
courses = models.ManyToManyField(
Course,
related_name='students',
through='StudentCourse'
)
class StudentCourse(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
cass Course(models.Model):
# ... other fields..."
我想要:
class Student(models.Model):
# ... other fields..."
course = models.ManyToManyField(Course, related_name='students')
class Course(models.Model):
# ... other fields..."
我无法在Django中找到一种方法来做到这一点而不丢失已经插入的数据。
我想以Django的方式重命名表,并操作Django迁移元数据,但这是一种丑陋的解决方法
Django有没有一种方法可以在不丢失数据(或创建备份表(的情况下解决这个问题?
首先创建一个空的迁移文件,该文件将填充我们的迁移操作
python manage.py makemigrations <app> --empty
然后,该迁移需要填充以下内容(<app>
应替换为应用程序的应用程序名称(
from django.db import migrations, models
def move_courses(apps, schema_editor):
Student = apps.get_model('<app>', 'Student')
StudentCourse = apps.get_model('<app>', 'StudentCourse')
for student in Student.objects.all():
student.courses.set(
StudentCourse.objects.filter(student=student).values_list('course', flat=True)
)
class Migration(migrations.Migration):
dependencies = [
('<app>', '<XXXX_previous_migration_name>'),
]
operations = [
# Remove the old ManyToManyField
# This won't delete the through table or it's data
migrations.RemoveField(
model_name='Student',
name='courses',
),
# Add the new ManyToManyField
migrations.AddField(
model_name='Student',
name='courses',
field=models.ManyToManyField(related_name='students', to='<app>.Course'),
),
# Run a script that copies data from the old through table to the new one
migrations.RunPython(move_courses),
# Delete the old through table
migrations.DeleteModel(
name='StudentCourse',
),
]
然后以您喜欢的方式更新您的模型:
class Student(models.Model):
# ... other fields..."
courses = models.ManyToManyField(
Course,
related_name='students',
)
# Since through='StudentCourse' was removed, below is removed to (keeping it as comment to represent the removal)
# class StudentCourse(models.Model):
# student = models.ForeignKey(Student, on_delete=models.CASCADE)
# course = models.ForeignKey(Course, on_delete=models.CASCADE)
class Course(models.Model):
# ... other fields..."
更新模型和空创建的迁移后,可以运行migrate
python manage.py migrate
重要提示:不要再运行makemigrations
,只运行migrate
,以便Django运行移动数据的迁移。