Подтвердить что ты не робот

Ошибка миграции 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, поэтому любые предложения приветствуются.

4b9b3361

Ответ 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.