Ошибка миграции Django: вы не можете изменять поля M2M или из них, а также добавлять или удалять через = по полям M2M
Я пытаюсь изменить поле M2M в поле ForeignKey. Команда validate не показывает никаких проблем, и когда я запускаю syncdb:
ValueError: Cannot alter field xxx into yyy they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
Так что я не могу сделать миграцию.
class InstituteStaff(Person):
user = models.OneToOneField(User, blank=True, null=True)
investigation_area = models.ManyToManyField(InvestigationArea, blank=True,)
investigation_group = models.ManyToManyField(InvestigationGroup, blank=True)
council_group = models.ForeignKey(CouncilGroup, null=True, blank=True)
#profiles = models.ManyToManyField(Profiles, null = True, blank = True)
profiles = models.ForeignKey(Profiles, null = True, blank = True)
Это мой первый проект Django, поэтому любые предложения приветствуются.
Ответы
Ответ 1
Я наткнулся на это, и хотя я не очень заботился о своих данных, я все равно не хотел удалять всю БД. Поэтому я открыл файл миграции и изменил команду AlterField()
на команду RemoveField()
и AddField()
, которая хорошо работала. Я потерял свои данные в конкретной области, но ничего больше.
т.е.
migrations.AlterField(
model_name='player',
name='teams',
field=models.ManyToManyField(related_name='players', through='players.TeamPlayer', to='players.Team'),
),
к
migrations.RemoveField(
model_name='player',
name='teams',
),
migrations.AddField(
model_name='player',
name='teams',
field=models.ManyToManyField(related_name='players', through='players.TeamPlayer', to='players.Team'),
),
Ответ 2
Возможные обходные пути:
-
Создайте новое поле с отношением ForeignKey под названием profiles1
и НЕ изменяйте profiles
. Сделайте и запустите миграцию. Для предотвращения конфликтов может потребоваться параметр related_name
. Сделайте последующую миграцию, которая отбрасывает исходное поле. Затем выполните другую миграцию, которая переименовывает profiles1
обратно в profiles
. Очевидно, что у вас не будет данных в новом поле ForeignKey.
-
Напишите пользовательскую миграцию: https://docs.djangoproject.com/en/1.7/ref/migration-operations/
Возможно, вы захотите использовать makemigration
и migration
, а не syncdb
.
Есть ли у вашего InstituteStaff
данные, которые вы хотите сохранить?
Ответ 3
НЕТ ПРИМЕРА ПОТЕРИ ДАННЫХ
Я бы сказал: если машина не может что-то сделать для нас, то пусть поможет!
Поскольку проблема, которую ставит здесь OP, может иметь несколько мутаций, я постараюсь объяснить, как бороться с такой проблемой простым способом.
Предположим, у нас есть модель (в приложении под названием users
), подобная этой:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person)
def __str__(self):
return self.name
но через некоторое время нам нужно добавить дату присоединения участника. Итак, мы хотим это:
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership') # <-- through model
def __str__(self):
return self.name
# and through Model itself
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
Теперь обычно вы сталкиваетесь с той же проблемой, что и OP. Чтобы решить эту проблему, выполните следующие действия:
начать с этого момента:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person)
def __str__(self):
return self.name
создать через модель и запустить python manage.py makemigrations
(, но пока не помещайте свойство through
в поле Group.members
):
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person) # <-- no through property yet!
def __str__(self):
return self.name
class Membership(models.Model): # <--- through model
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
создайте пустую миграцию с помощью команды python manage.py makemigrations users --empty
и создайте скрипт преобразования в python (подробнее о миграциях python здесь), который создает новые отношения (Membership
) для старого поля (Group.members
). Это может выглядеть так:
# Generated by Django A.B on YYYY-MM-DD HH:MM
import datetime
from django.db import migrations
def create_through_relations(apps, schema_editor):
Group = apps.get_model('users', 'Group')
Membership = apps.get_model('users', 'Membership')
for group in Group.objects.all():
for member in group.members.all():
Membership(
person=member,
group=group,
date_joined=datetime.date.today()
).save()
class Migration(migrations.Migration):
dependencies = [
('myapp', '0005_create_models'),
]
operations = [
migrations.RunPython(create_through_relations, reverse_code=migrations.RunPython.noop),
]
удалите поле members
в модели Group
и запустите python manage.py makemigrations
, чтобы наш Group
выглядел следующим образом:
class Group(models.Model):
name = models.CharField(max_length=128)
Добавьте в поле members
модель Group
, но теперь со свойством through
и запустите python manage.py makemigrations
:
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
и это оно!
Теперь вам нужно по-новому изменить создание элементов в вашем коде - через модель. Подробнее о здесь.
Вы также можете убрать его, подавив эти миграции.
Ответ 4
Если вы все еще разрабатываете приложение и не нуждаетесь в сохранении существующих данных, вы можете обойти эту проблему, выполнив следующие действия:
-
Удалите и заново создайте db.
-
перейдите в папку проекта/приложения/миграции
-
Удалите все в этой папке, за исключением файла init.py. Убедитесь, что вы также удалили директорию pycache.
-
Запустите syncdb, makemigrations и migrate.