在django字段中添加“直通”表并与南方迁移?

时间:2011-05-19 18:40:31

标签: django django-south

似乎这应该是“容易的”或者至少在某处记录,我只是无法找到它。

假设我有一个模特:

class A(models.Model):
    users = models.ManyToMany('auth.User', blank=True)

现在我想迁移到一个through表来向ManyToMany关系添加字段......

class AUsers(models.Model):
    user = models.ForeignKey('auth.User')
    a = models.ForeignKey('A')
    new_field = models.BooleanField()

class A(models.Model):
    users = models.ManyToMany('auth.User', blank=True, through='AUsers')

然后我这样做:

% ./manage.py schemamigration app --auto

并不完全令人惊讶,它告诉我它将删除原始自动创建的表并为AUsers创建一个新的。目前最好的做法是什么?是否有适当的方法迁移到新的through表?我在Meta中使用db_table吗?我是不是马上使用through=... ...然后执行schemamigration --auto,然后执行datamigration复制当前表(不知何故,不确定...)然后添加through关系,让它杀死桌子?

这里的诀窍是什么?这真的很难吗?

3 个答案:

答案 0 :(得分:14)

你应该可以很容易地做到这一点。

首先,确保您创建的手动表在数据库中具有与Django最初自动创建的表名相同的表名。

因此,首先,让我们在您做出改变之前考虑手动通过模型:

class AUsers(models.Model):
    user = models.ForeignKey('auth.User')
    a = models.ForeignKey('A')

    class Meta:
        db_table = 'appname_a_user'

这应该在功能上(几乎)与您曾经拥有的ManyToManyField相同。实际上,你可以进行空迁移并应用它,然后使用--auto进行更改(但不要)。

现在,像上面的示例代码中一样添加字段,然后运行./manage.py schemamigration appname manual_through_table --empty。这将为您提供名为####_manual_through_table.py的空迁移。

在迁移本身中,会有forwardsbackwards方法。每个人都需要一行:

def forwards(self, orm):
    db.add_column('appname_a_user', 'new_field', self.gf('django.db.models.fields.BooleanField')(default=False))

def backwards(self, orm):
    db.delete_column('appname_a_user', 'new_field')

那应该能让你得到你想要的东西。

答案 1 :(得分:5)

如果有人在尝试使用现代迁移框架执行相同操作时遇到此问题,请执行以下步骤:

  1. 创建一个与内置表格完全匹配的新模型类
  2. 使用Meta类设置表名以匹配现有表
  3. 生成迁移,该迁移将创建新表并将其设置为字段的直通。
  4. 如果不运行该迁移,请对其进行编辑以将其包装在migrations. SeparateDatabaseAndState迁移中,其中自动生成的步骤位于state_operations字段中,并且数据库操作为空。
  5. 根据需要修改直通表,确保正常生成新的迁移。

答案 2 :(得分:0)

正如评论中所提到的,可以使用db.rename_table简化第一步,如here所述,通过模型提供此内容:

class AUsers(models.Model):
user = models.ForeignKey('auth.User')
a = models.ForeignKey('A')

class Meta:
    unique_together = (('user', 'a'),)

然后,使用--auto创建迁移(这样您就可以看到数据库表的名称),并将内容替换为:

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('appname_a_user', 'appname_auser')

    def backwards(self, orm):
        db.rename_table('appname_auser','appname_a_user') 

我刚刚在我的项目中应用它而没有任何问题。