2012-12-19 52 views
3

让我们假设我创建了两个模型:Django的:转换ManyToManyField到FOREIGNKEY

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) 

我添加条目两种型号,然后我意识到,每辆车只涉及到一个独特的制造商。所以,我应该将我的ManyToManyField转换为外键:

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) 

我该怎么做,而不会丢失我的条目?我试图南文档中查找,但我没有找到转换的这种方式...

回答

7

这是平凡的,我想你会需要三个迁移:

  1. 添加ForeignKey
  2. ManyToMany转换为ForeignKey(使用forwards方法)。
  3. 删除ManyToMany

你可能会合并1和2或2和3在一起,但我不会推荐它。
此外,您还应该落实2.

例如一个backwards方法2的forwards是:

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() 

请注意:

  • 有这里还没有backwards方法。
  • 这需要进行广泛的测试:迁移是您应该特别注意的问题。
  • 如果汽车有两个制造商,最后一个将被保留。
  • 这是非常低效的,我们每个制造商做一个查询每辆车!

您还需要更新使用步骤的关系码2/3

+0

您能否提供汽车和制造商车型的前进方法示例? – gueux

+0

@gueux我更新了答案。 –

+0

mmh,第1步有问题:)如何将外键添加到汽车,因为制造商尚未定义?我得到一个:“NameError:name'制造商'未定义” – gueux

4

基于由托马斯·奥罗斯科提供了出色的答案,我想提供解决方案对于Django> = 1.7(基本上是指向2 将ManyToMany转换为ForeignKey在Django的新版本中有所不同)。所以在这里为第二迁移代码:

class Migration(migrations.Migration): 

    def migrate_m2m_to_fk(apps, schema_editor): 
     Manufacturer = apps.get_model("app", "Manufacturer") 
     for manufacturer in Manufacturer.objects.all(): 
      for car in manufacturer.car.all(): 
        car.manufacturer = manufacturer 
        car.save() 

    def migrate_fk_to_m2m(apps, schema_editor): 
     Car = apps.get_model("app", "Car") 
     for c in Car.objects.all(): 
      if c.manufacturer: 
       c.manufacturer.car.add(c) 
       c.manufacturer.save() 

    operations = [ 
     migrations.RunPython(migrate_m2m_to_fk, migrate_fk_to_m2m) 
    ] 

其中“应用程序”是Django应用程序,其中型号住。显示正向和反向迁移代码(正如Thomas提到的,运行此迁移可能会导致数据丢失,如果事先存在多个关系,请注意)。