在Django+;南方

在Django+;南方,django,django-south,Django,Django South,我使用Django和South作为我的数据库。现在我想在现有模型中添加一个新模型和一个字段,并引用新模型。例如: class NewModel(models.Model): # a new model # ... class ExistingModel(models.Model): # ... existing fields new_field = models.ForeignKey(NewModel) # adding this now 现在,Sout

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

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

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

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

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

在这种情况下,您需要数据迁移来补充模式迁移

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


在南方,期望的结果在两到三次架构/数据迁移中传播并不少见,因为不可能一次成功就完成(如果底层数据库允许添加非空列而没有默认值,则有时取决于底层数据库)。因此,在这种情况下,您可以添加一个具有默认值的模式迁移,然后添加一个带有对象操作的数据迁移,然后添加一个最终的模式迁移。

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

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

0001\u schema\u migration\u将\u exforeign\u key\u从\u existing\u model.py添加到\u new\u model\u

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)
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)
新型号.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事务的概念

为了避免不可避免地遇到的一些问题(包括我上面提到的错误和来自南方的错误,要求您将SchemaMigration中的
orm
项标记为
no dry run
),您需要更改上述
0001
脚本以执行以下操作:

0001\u schema\u migration\u将\u exforeign\u key\u从\u existing\u model.py添加到\u new\u model\u

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)
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)
然后,您可以正常运行新模型.py的
0002\u data\u migration\u文件


我建议对Postgres和MySql使用上述相同的示例。我不记得第一个示例中的Postgres有任何问题,但我确信第二个示例对这两个示例都有效(已测试).

最好将示例包含在您的答案中,而不是仅链接到它。如果该链接移动、消失或不可用,您的答案将毫无帮助。