many - Error de migración de Django: no puede alterar desde o hacia campos M2M, o agregar o eliminar a través de=en campos M2M
manytomany django (4)
Estoy tratando de modificar un campo M2M a un campo ForeignKey. El comando validar no me muestra problemas y cuando ejecuto 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)
Así que no puedo hacer la migración.
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)
Este es mi primer proyecto de Django, así que cualquier sugerencia es bienvenida.
Me tropecé con esto y aunque no me importaban mucho mis datos, todavía no quería eliminar toda la base de datos. Así que abrí el archivo de migración y cambié el AlterField()
a un RemoveField()
y un AddField()
que funcionó bien. Perdí mis datos en el campo específico, pero nada más.
Es decir
migrations.AlterField(
model_name=''player'',
name=''teams'',
field=models.ManyToManyField(related_name=''players'', through=''players.TeamPlayer'', to=''players.Team''),
),
a
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''),
),
Posibles soluciones:
Cree un nuevo campo con la relación ForeignKey llamada
profiles1
y NO modifique losprofiles
. Realiza y ejecuta la migración. Es posible que necesite un parámetrorelated_name
para evitar conflictos. Hacer una migración posterior que suelte el campo original. Luego realice otra migración que cambie el nombre deprofiles1
aprofiles
. Obviamente, no tendrá datos en el nuevo campo ForeignKey.Escriba una migración personalizada: https://docs.djangoproject.com/en/1.7/ref/migration-operations/
Es posible que desee utilizar makemigration
y la migration
lugar de syncdb
.
¿Tiene su InstituteStaff
datos que desea conservar?
Si aún está desarrollando la aplicación y no necesita conservar sus datos existentes, puede solucionar este problema haciendo lo siguiente:
Eliminar y volver a crear la db.
Ve a tu carpeta de proyecto / aplicación / migraciones
Elimine todo en esa carpeta con la excepción del archivo init .py. Asegúrate de eliminar también el directorio de pycache .
Ejecute syncdb, makemigrations y migre.
Yo diría: ¡Si la máquina no puede hacer algo por nosotros, entonces ayudémoslo!
Debido a que el problema que OP pone aquí puede tener múltiples mutaciones, trataré de explicar cómo luchar con ese tipo de problema de una manera sencilla.
Supongamos que tenemos un modelo (en la aplicación llamado users
) como este:
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
pero después de un tiempo necesitamos agregar una fecha de ingreso a un miembro. Así que queremos esto:
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()
Ahora, normalmente tendrás el mismo problema que escribió OP. Así que en ese caso volvemos a lo que escribí al principio, ayudando así a la máquina. Podemos lograr ese objetivo en los siguientes pasos:
empezar desde este punto:
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
cree a través del modelo y ejecute
python manage.py makemigrations
( pero no ponga propiedad athrough
del campoGroup.members
todavía ):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()
cree una migración vacía con los
python makemigrations users --empty
command y cree un script de conversión en python (más información sobre las migraciones de python here ) que crea nuevas relaciones (Membership
) para un campo antiguo (Group.members
). Podría verse así:# 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), ]
elimine el campo de
members
en el modelo deGroup
y ejecute laspython manage.py makemigrations
, para que nuestroGroup
se vea así:class Group(models.Model): name = models.CharField(max_length=128)
agregue
members
campo del modelo deGroup
, pero ahora con propiedad y ejecutepython manage.py makemigrations
:class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through=''Membership'')
¡y eso es! Ahora necesita cambiar la creación de miembros de una nueva forma en su código: a través del modelo. Más sobre here .