Erreur de migration de Django: vous ne pouvez pas modifier vers ou depuis les champs M2M, ou ajouter ou supprimer VIA= sur les champs M2M
j'essaie de modifier un champ M2M en champ ForeignKey. La commande Valider ne me montre aucun problème et quand j'exécute 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)
donc je ne peux pas faire la migration.
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)
C'est mon premier projet Django donc toutes les suggestions sont les bienvenues.
4 réponses
je suis tombé sur ceci et bien que je ne me souciais pas beaucoup de mes données, Je ne voulais pas supprimer tout le DB. J'ai donc ouvert le fichier de migration et changé le AlterField()
commande RemoveField()
et AddField()
commande qui a bien fonctionné. J'ai perdu mes données sur le terrain, mais rien d'autre.
I. E.
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'),
),
solutions de rechange possibles:
Créer un nouveau champ avec le ForeignKey relation appelée
profiles1
et ne modifiez pasprofiles
. Faire et exécuter la migration. Vous pourriez avoir besoin d'unrelated_name
paramètre pour prévenir les conflits. Faire une migration subséquente qui fait tomber le champ original. Puis faites une autre migration qui renommeprofiles1
retourprofiles
. Évidemment, vous n'aurez pas de données dans le nouveau champ ForeignKey.écrire une migration personnalisée: https://docs.djangoproject.com/en/1.7/ref/migration-operations/
Vous pouvez utiliser makemigration
et migration
plutôt que syncdb
.
votre InstituteStaff
disposons de données que vous souhaitez conserver?
si vous êtes encore en train de développer l'application, et que vous n'avez pas besoin de préserver vos données existantes, vous pouvez contourner ce problème en faisant ce qui suit:
supprimer et recréer la base de données.
allez dans votre dossier projet/app/migrations
supprimez tout dans ce dossier à l'exception de init.dossier py. Assurez-vous que vous supprimez aussi le pycache dir.
Lancez syncdb, makemigrations, et migrate.
je dirais: si machine ne peut pas faire quelque chose pour nous, alors aidons-le!
parce que le problème que OP a mis ici peut avoir de multiples mutations, je vais essayer d'expliquer comment lutter avec ce genre de problème d'une manière simple.
imaginons que nous avons un modèle (dans l'application appelée users
) comme ceci:
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
mais après tout nous avons besoin d'ajouter une date d'un membre de la rejoindre. Nous voulons donc ceci:
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()
Maintenant, normalement, vous j'ai eu le même problème que L'OP a écrit. Dans ce cas, on revient sur ce que j'ai écrit au début, donc on AIDE la machine. Nous pouvons atteindre cet objectif en les étapes suivantes:
démarrer à partir de ce point:
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
créer un modèle et run
python manage.py makemigrations
( mais ne mettez pasthrough
propriétéGroup.members
terrain):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()
créer une migration vide en utilisant
python makemigrations users --empty
commande et création script de conversion en python (en savoir plus sur les migrations python ici) qui crée de nouvelles relations (Membership
) pour un ancien champ (Group.members
). Il pourrait ressembler à ceci:# 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') 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), ]
supprimer
members
champGroup
modéliser et exécuterpython manage.py makemigrations
, de sorte que notreGroup
ressemblera à ceci:class Group(models.Model): name = models.CharField(max_length=128)
ajouter
members
le champGroup
modèle, mais maintenant, avecthrough
propriété et courirpython manage.py makemigrations
:class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership')
et c'est tout! Maintenant, vous devez créer le changement des membres d'une manière nouvelle dans votre code par modèle. Plus sur ici.