如何在使用ManyToMany字段的'through'时使用south迁移?

5 投票
3 回答
850 浏览
提问于 2025-04-17 04:54

我想在一个Django应用中修改一个多对多的字段。

我有以下这些模型:

class A:
    ...

class B:
    as = models.ManyToManyField(A)

我想要的是:

class A:
    ...

class C:
     a = models.ForeignKey(A)
     b = models.ForeignKey("B")
     extra_data = models.BooleanField(default=False)

class B:
    as = models.ManyToManyField(A, through=C)

我在使用south来进行数据库迁移。不幸的是,在这种情况下,south建议删除现有的 app_b_a 表,然后重新创建一个新的 app_c

有没有办法告诉south不要重新创建这个多对多的表?

3 个回答

0

你也可以试着把C的db_table参数设定为'app_b_a'。不过我不确定这样做是否有效。

2

我最近也遇到过这个问题,其实挺简单的。

首先,先在你的代码里添加一个新的中间模型,但不要把它指定为ManyToManyFieldthrough参数。接下来,创建一个自动的模式迁移,这样就会为你生成一个新的表。

$ python manage.py schemamigration --auto yourapp

第二步,创建一个数据迁移:

$ python manage.py datamigration yourapp name_of_migration

在你的前向迁移中:

for b in orm.B.objects.all():
    for a in b.as.all():
        orm.C.objects.create(a=a, b=b)

在你的后向迁移中:

for c in orm.C.objects.all():
    c.b.as.add(a)

最后,把through参数添加到你的ManyToManyField里,然后再生成一个自动的模式迁移:

$ python manage.py schemamigration --auto yourapp
6

我会这样做:

  1. 先添加一个 C 模型,但不要添加任何额外的数据字段。只需要把两个外键(FK)设置为关联的模型,这样它的结构就和默认的多对多(m2m)表几乎一样,只是表名不同。
  2. 为你的应用运行 schemamigration --auto
  3. 为了有效地“删除”现有的表并“创建”一个新的表,而不移动数据,只需删除 forwardsbackwards 方法中生成的所有迁移代码,然后添加: forwards: db.rename_table('yourappname_m2mtablename', 'yourappname_c') backwards: db.rename_table('yourappname_c', 'yourappname_m2mtablename')
  4. 保持“冻结”的模型字典不变!
  5. 现在你可以扩展你的 C 模型,并为它生成一个新的迁移。

撰写回答