添加“通过”表到 django 字段并随 South 迁移?

发布于 2024-11-08 16:29:47 字数 924 浏览 4 评论 0原文

看起来这应该是“简单”的,或者至少在某个地方有记录,我只是找不到它。

假设我有一个模型:

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

这里有什么技巧呢?这真的有那么难吗?

Seems like this should be "easy" or at least documented somewhere, I just cant find it.

Lets say I have a model:

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

Now I want to migrate to have a through table to add fields to the ManyToMany relation...

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

Then I do:

% ./manage.py schemamigration app --auto

Not totally surprising, it tells me it is going to drop the original auto-created through table and create a new one for AUsers. What's the best practice at this point? Is there a decent way to migrate to the new through table? Do I use db_table in Meta? Do I just not use the through=... right away... then do a schemamigration --auto, then a datamigration to copy the current table (somehow, not sure...) and then add the through relation and let it kill the table?

What's the trick here? Is this really that hard?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

念三年u 2024-11-15 16:29:47

您应该能够很轻松地做到这一点。

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

这应该可以满足您的需求。

You should be able to do this pretty easily.

First of all, make sure that the manual through table that you are creating has the same table name in the database as the one Django originally created automatically.

So, first, let's consider a manual through model before your change:

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

    class Meta:
        db_table = 'appname_a_user'

That should be functionally (almost) identical to the ManyToManyField you used to have. Actually, you could make an empty migration and apply it, and then use --auto for your changes (but don't).

Now, add your field like you did in your sample code above, and then run ./manage.py schemamigration appname manual_through_table --empty. That will give you an empty migration named ####_manual_through_table.py.

In the migration itself, there will be a forwards and backwards method. Each one needs to be one line each:

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

That should get you what you are after.

请爱~陌生人 2024-11-15 16:29:47

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

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

If anyone comes across this question when trying to do the same thing with the moderns migration framework, here are the steps:

  1. Create a new model class that exactly matches the built-in through table
  2. Use the Meta class to set the table name to match the existing table
  3. Generate a migration, which will create the new table and set it as the through for the field.
  4. Without running that migration, edit it to wrap it in a migrations. SeparateDatabaseAndState migration, where the auto-generated steps are in the state_operations field and the database operations are empty.
  5. Modify your through table, as required, making sure to generate new migrations as normal.
独留℉清风醉 2024-11-15 16:29:47

正如评论中提到的,第一步可以使用 < code>db.rename_table此处所述,通过模型给出:

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

我刚刚将其应用到我的项目中,没有出现问题。

As mentioned in a comment, the first step may be simplified using db.rename_table as described here, which gives this through model:

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

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

Then, create a migration with --auto (this way you'll have the names of the DB tables visible), and replace the content with:

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

I just applied it in my project without issues.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文