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

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

最佳答案

最简单的方法是写一个schemamigration让列发生变化,然后写一个datamigration来正确填入值。根据您使用的数据库,您必须以略有不同的方式执行此操作。
Sqlite
对于 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 要求您将 SchemaMigration 中的 orm 项目标记为 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 有任何问题,但我确定第二个示例适用于两者(经过测试)。

关于django - 在 Django+South 中添加一个非空的外键字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15956757/

相关文章:

python - Django-URL 命名空间

django - 如何在 Heroku 上使用 Django 将位于 URL 的图像保存到 S3?

django - ImportError : No module named south. v2 但我不使用南

Django 迁移缺少声明 "needed_by"的方法?

django - 如何设置运行Django的AWS Elastic Beanstalk Docker平台?

python - 如何使用 F 表达式在 update() 中为每个 PointField 分配纬度和经度?

django - 表单中捕获的 URL 参数

python - Django South - 从 Python 代码迁移

python - 使用 django+south 迁移更改表的编码

python - Django:以编程方式/动态创建数据库表