J'essaie de modifier un champ M2M en un champ ForeignKey. La commande validate ne me montre aucun problème et lorsque 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)
Je ne peux donc pas effectuer 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)
Ceci est mon premier projet Django donc toutes les suggestions sont les bienvenues.
Je suis tombé sur cela et bien que je ne me soucie pas beaucoup de mes données, je ne voulais toujours pas supprimer la base de données entière. J'ai donc ouvert le fichier de migration et changé la commande AlterField()
en RemoveField()
et AddField()
qui fonctionnait bien. J'ai perdu mes données sur le domaine spécifique, mais rien d'autre.
C'est à dire.
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 contournement potentielles:
Créez un nouveau champ avec la relation ForeignKey appelée profiles1
et NE modifiez PAS profiles
. Effectuez et exécutez la migration. Vous pourriez avoir besoin d'un related_name
paramètre pour éviter les conflits. Effectuez une migration ultérieure qui supprime le champ d'origine. Effectuez ensuite une autre migration qui renomme profiles1
retour à profiles
. De toute évidence, vous n'aurez pas de données dans le nouveau champ ForeignKey.
Écrivez une migration personnalisée: https://docs.djangoproject.com/en/1.7/ref/migration-operations/
Vous souhaiterez peut-être utiliser makemigration
et migration
plutôt que syncdb
.
Votre InstituteStaff
contient-elle des données que vous souhaitez conserver?
Je dirais: si la machine ne peut pas faire quelque chose pour nous, alors aidons-la!
Parce que le problème que OP pose ici peut avoir plusieurs mutations, je vais essayer d'expliquer comment lutter avec ce type de problème de manière simple.
Supposons que nous ayons 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 un certain temps, nous devons ajouter une date de membre. 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 rencontrerez le même problème que l'OP a écrit. Pour le résoudre, procédez comme suit:
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 via le modèle et exécuter python manage.py makemigrations
( mais ne mettez pas la propriété through
dans le Group.members
champ encore ):
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 à l'aide de python makemigrations users --empty
commande et créer un script de conversion dans python (plus sur les migrations python ici ) qui crée de nouvelles relations (Membership
) pour un ancien champ (Group.members
). Cela 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')
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),
]
supprimer le champ members
dans le modèle Group
et exécuter python manage.py makemigrations
, donc notre Group
ressemblera à ceci:
class Group(models.Model):
name = models.CharField(max_length=128)
ajoutez members
champ le modèle Group
, mais maintenant avec la propriété through
et exécutez python manage.py makemigrations
:
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
et c'est tout!
Vous devez maintenant modifier la création de membres d'une nouvelle manière dans votre code - par le biais du modèle. En savoir plus sur ici .
Vous pouvez également éventuellement le ranger, en écraser ces migrations.
Si vous développez toujours l'application et n'avez pas besoin de conserver vos données existantes, vous pouvez contourner ce problème en procédant comme suit:
Supprimez et recréez la base de données.
allez dans votre dossier project/app/migrations
Supprimez tout dans ce dossier à l'exception du fichier init. Py. Assurez-vous de supprimer également le répertoire pycache .
Exécutez syncdb, makemigrations et migrez.