7

我使用 Django 和 South 作为我的数据库。现在我想在现有模型中添加一个新模型和一个字段,引用新模型。例如:

class NewModel(models.Model):
    # a new model
    # ... 

class ExistingModel(models.Model):
    # ... existing fields

    new_field = models.ForeignKey(NewModel)  # adding this now

现在 South 显然抱怨我添加了一个非空字段并要求我输入一次性值。但我真正想要的是NewModel为每个现有实例创建一个新实例ExistingModel,从而满足数据库要求。这有可能吗?

4

2 回答 2

9

执行此操作的最简单方法是编写使列更改的架构迁移,然后编写数据迁移以正确填写值。根据您使用的数据库,您必须以稍微不同的方式执行此操作。

方镁石

对于 Sqlite,您可以为关系添加一个标记值并使用数据迁移来填写它,而不会出现任何问题:

0001_schema_migration_add_foreign_key_to_new_model_from_existing_model.py

from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):
    
    def forwards(self, orm):
        db.add_column('existing_model_table', 'new_model',
                      self.gf('django.db.models.fields.related.ForeignKey')(default=0, to=orm['appname.new_model']), keep_default=False)

0002_data_migration_for_new_model.py

class Migration(DataMigration):
    
    def forwards(self, orm):
        for m in orm['appname.existing_model'].objects.all():
            m.new_model = #custom criteria here
            m.save()
    

这将工作得很好,没有问题。

Postgres 和 MySQL

使用 MySql,你必须给它一个有效的默认值。如果0它实际上不是一个有效的外键,你会得到错误告诉你。

可以默认为 1,但在某些情况下这不是有效的外键(发生在我身上是因为我们有不同的环境,并且某些环境发布到其他数据库,因此 ID 很少匹配(我们使用 UUID 进行交叉数据库识别,如上帝所愿)。

您遇到的第二个问题是 South 和 MySQL 不能很好地协同工作。部分原因是 MySQL 没有 DDL 事务的概念。

为了解决您将不可避免地遇到的一些问题(包括我上面提到的错误以及 South 要求您将ormSchemaMigration 中的项目标记为no-dry-run),您需要更改上述0001脚本以执行以下操作:

0001_schema_migration_add_foreign_key_to_new_model_from_existing_model.py

from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):
    
    def forwards(self, orm):
        id = 0
        if not db.dry_run:
            new_model = orm['appname.new_model'].objects.all()[0]
            if new_model:
                id = new_model.id
        db.add_column('existing_model_table', 'new_model',
                      self.gf('django.db.models.fields.related.ForeignKey')(default=id, to=orm['appname.new_model']), keep_default=False)

然后您可以0002_data_migration_for_new_model.py正常运行该文件。

我建议对 Postgres 和 MySql 使用上面相同的示例。我不记得第一个示例与 Postgres 的任何问题,但我确信第二个示例适用于两者(经过测试)。

于 2013-07-11T18:38:49.820 回答
6

在这种情况下,您希望数据迁移来补充您的架构迁移。

South 有一个很好的分步教程,关于如何在文档中实现这一点,这里

在南方,将期望的结果分布在两个或三个模式/数据迁移上并不少见,因为它并不总是可能在一次大命中中做到这一点(有时取决于底层数据库是否可以容忍添加一个没有默认值的非空列)。因此,在这种情况下,您可能会添加一个具有默认值的模式迁移,然后是使用您的对象操作进行数据迁移,然后是最终模式迁移。

于 2013-04-11T19:20:39.973 回答