Как перейти от M2M, созданного с помощью 'through', к M2M, управляемому Django
Я работаю в проекте, где было несколько полей, созданных как M2M с помощью through
связанной модели, однако они были созданы неправильно, а связанные модели не имеют дополнительных полей, поэтому я хотел бы использовать обычный M2M, управляемый Django.
Существующие модели, которые у меня есть:
cass Student(models.Model):
# ... other fields..."
course = 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.course.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='course',
),
# Add the new ManyToManyField
migrations.AddField(
model_name='student',
name='course',
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',
),
]