2011-05-19 36 views
13

看起来像这样应该是“容易”或至少记录在某个地方,我只是无法找到它。将“through”表添加到django字段并使用South迁移?

可以说我有一个模型:

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

现在我想迁移到有一个through表字段添加到多对多关系...

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关系,让它杀死表?

这里有什么窍门?这真的很难吗?

回答

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

这应该让你得到你想要的。

+0

是的,我有点想知道这是否需要手动迁移。看起来,既然你也这样想......那是对的。 db_table也是我想我也必须要做的。只是看起来像只是因为它的迁移历史而不存在的“残余”,但我想这就是我要做的。我会标记接受,如果/当它的工作。 – dlamotte 2011-05-19 20:24:08

+1

您还需要添加unique_constraint以使迁移“完成”。我觉得这有点太复杂了......至少比它需要的更多?我会把这个开放几天,看看有人有更好的解决方案...我想看到一个...也许我需要破解南加入未来? – dlamotte 2011-05-19 20:55:26

+0

@dlamotte我自己也会遇到同样的情况。你可以(现在,我不知道那时候)使用'db.rename_table'将表名改为任何你想要的。 – antitoxic 2015-07-07 15:19:34

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

我刚刚应用在我的项目没有问题。

3

如果有人遇到试着用现代人迁移框架同样的事情时这个问题,这里的步骤:

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