执行此操作的最简单方法是编写使列更改的架构迁移,然后编写数据迁移以正确填写值。根据您使用的数据库,您必须以稍微不同的方式执行此操作。
方镁石
对于 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 要求您将orm
SchemaMigration 中的项目标记为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 的任何问题,但我确信第二个示例适用于两者(经过测试)。