mercredi 13 août 2014

python - Django : convertir ManyToManyField ForeignKey - Stack Overflow


Let's supposed I created two models:


class Car(models.Model):
name = models.CharField(max_length=50)
size = models.IntegerField()


class Manufacturer(models.Model):
name = models.CharField(max_length=50)
country = models.CharField(max_length=50)
car = models.ManyToManyField(Car)

I added entries to both models, then I realized that each Car was only related to a unique Manufacturer. So, I should convert my ManyToManyField to a ForeignKey:


class Car(models.Model):
name = models.CharField(max_length=50)
size = models.IntegerField()
manufacturer = models.ForeignKey(Manufacturer)

class Manufacturer(models.Model):
name = models.CharField(max_length=50)
country = models.CharField(max_length=50)

How can I do that without losing my entries? I tried to look in South documentation but I did not found this way of conversion...




This is nontrivial, I think you will need three migrations:



  1. Add the ForeignKey.

  2. Convert the ManyToMany to ForeignKey (using the forwards method).

  3. Remove the ManyToMany.


You could possibly merge 1 and 2 or 2 and 3 together, but I wouldn't recommend it.
Additionally, you should also implement a backwards method for 2.


An example for 2.'s forwards would be:


class Migration(SchemaMigration):
def forwards(self, orm):
for manufacturer in orm.Manufacturer.objects.all():
for car in manufacturer.car.all():
car.manufacturer = manufacturer
car.save()

Please note that:



  • There is no backwards method here yet.

  • This needs to be tested extensively: a migration is something you should be extra careful about.

  • In case a car has two manufacturers, the last one will be kept.

  • This is very inefficient, we do a Query per car per manufacturer!




You will also need to update the code that uses those relationships in step 2. / 3.



Let's supposed I created two models:


class Car(models.Model):
name = models.CharField(max_length=50)
size = models.IntegerField()


class Manufacturer(models.Model):
name = models.CharField(max_length=50)
country = models.CharField(max_length=50)
car = models.ManyToManyField(Car)

I added entries to both models, then I realized that each Car was only related to a unique Manufacturer. So, I should convert my ManyToManyField to a ForeignKey:


class Car(models.Model):
name = models.CharField(max_length=50)
size = models.IntegerField()
manufacturer = models.ForeignKey(Manufacturer)

class Manufacturer(models.Model):
name = models.CharField(max_length=50)
country = models.CharField(max_length=50)

How can I do that without losing my entries? I tried to look in South documentation but I did not found this way of conversion...



This is nontrivial, I think you will need three migrations:



  1. Add the ForeignKey.

  2. Convert the ManyToMany to ForeignKey (using the forwards method).

  3. Remove the ManyToMany.


You could possibly merge 1 and 2 or 2 and 3 together, but I wouldn't recommend it.
Additionally, you should also implement a backwards method for 2.


An example for 2.'s forwards would be:


class Migration(SchemaMigration):
def forwards(self, orm):
for manufacturer in orm.Manufacturer.objects.all():
for car in manufacturer.car.all():
car.manufacturer = manufacturer
car.save()

Please note that:



  • There is no backwards method here yet.

  • This needs to be tested extensively: a migration is something you should be extra careful about.

  • In case a car has two manufacturers, the last one will be kept.

  • This is very inefficient, we do a Query per car per manufacturer!




You will also need to update the code that uses those relationships in step 2. / 3.


0 commentaires:

Enregistrer un commentaire