【问题标题】:Adding a "through" table to django field and migrating with South?向 django 字段添加“通过”表并与 South 一起迁移?
【发布时间】:2011-08-29 03:12:09
【问题描述】:

似乎这应该是“简单的”或至少记录在某个地方,我只是找不到它。

假设我有一个模型:

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 关系并让它会毁了桌子吗?

这里有什么诀窍?真的有那么难吗?

【问题讨论】:

    标签: django django-south


    【解决方案1】:

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

    首先,确保您正在创建的手动通过表在数据库中与 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')
    

    这应该会让你得到你所追求的。

    【讨论】:

    • 是的,我有点想知道这是否是必需的手动迁移。看来,既然你也这么想……那就对了。 db_table 也是我想我也必须做的事情。似乎只是因为它的迁移历史而存在而不是必要的“杂物”......但我想这就是我要做的。如果/何时有效,我会标记接受。
    • 您还需要添加 unique_constraint 以使迁移“完成”。我觉得这有点太复杂了……至少比它需要的要复杂吗?我会让这个开放几天,看看是否有人有更好的解决方案......我想看看......也许我需要破解 South 以在未来添加它?
    • @dlamotte 自己也遇到了同样的情况。您可以(现在,我不知道当时)使用db.rename_table 将表名更改为您想要的任何名称。
    【解决方案2】:

    如果有人在尝试使用现代迁移框架做同样的事情时遇到这个问题,请按照以下步骤操作:

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

    【讨论】:

    • 编辑添加示例惨遭失败...这里有一个link 示例以避免混淆
    【解决方案3】:

    正如评论中提到的,第一步可以使用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') 
    

    我刚刚将它应用到我的项目中,没有任何问题。

    【讨论】:

      猜你喜欢
      • 2012-05-19
      • 1970-01-01
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      • 2014-01-12
      • 2013-04-19
      • 2012-08-06
      • 2012-08-13
      相关资源
      最近更新 更多