在最新的Django(2.2)中,当我像这样向模型添加一个新字段时:
new_field= models.BooleanField(default=False)
字符串
Django为MySQL运行以下命令:
ALTER TABLE `app_mymodel` ADD COLUMN `new_field` bool DEFAULT b'0' NOT NULL;
ALTER TABLE `app_mymodel` ALTER COLUMN `new_field` DROP DEFAULT;
COMMIT;
型
虽然这在所有内容都更新时有效,但这是非常有问题的,因为旧版本的应用程序在运行此迁移后无法再创建模型(它们不知道new_field
)。
2条答案
按热度按时间yhuiod9q1#
为什么不保留
DEFAULT
约束?因为Django在应用程序级别处理
default
模型字段选项,而不是数据库级别。所以真实的问题是为什么它设置DEFAULT
约束。关于第一点,历史上Django不支持模型字段的数据库级默认值。总是有一些人对改变这一点感兴趣(关于这个主题的first issue已经有18年的历史了),当然其他框架(Rails,我想,和SQLAlchemy)表明这是可能的。
最近,Django添加了一个名为
db_default
的单独字段选项。default
的行为保持不变,并且在应用程序级别处理默认值有很好的理由。例如:表达任意复杂计算的能力;不必担心数据库引擎之间的微妙不兼容性;在代码中示例化新示例并立即访问默认值的能力;在表单中向用户呈现默认值的能力;等等。现在,向现有数据库添加一个新的不可空字段是一个非常不同的用例。在这种情况下,您必须为数据库提供一个默认值,以便它执行操作。
makemigrations
将尝试从您的default
选项中推断正确的值,如果可以的话,如果没有,它会强制你从命令行指定一个值。所以DEFAULT
修饰符被用于这个有限的目的,然后被删除。正如你所注意到的,Django中缺少数据库级别的默认值会使持续部署变得更加困难。但是解决方案相当简单:只需在迁移中重新添加默认值。迁移系统的一个巨大好处是,它可以轻松地在Django的ORM之外对数据库进行任意,可重复,可测试的更改。所以只需添加一个新的RunSQL迁移操作:
字符串
您可以将其放入新的迁移文件中,或者简单地编辑自动生成的文件。根据您的数据库及其对事务性迁移的支持,操作序列可能是原子的,也可能不是原子的。
7y4bm7vi2#
我发现这张票从2年前:https://code.djangoproject.com/ticket/28000
其中指出:
**Django使用数据库默认值来设置表中现有行的值。它不会将默认值保留在数据库中,因此删除默认值是正确的行为。**在这种情况下,可能有一个优化,即不设置/删除默认值-我不确定是否需要,因为该列不是null。可以为此打开一个单独的工单。
我在这里的另一个问题中也看到了同样的引用:Django Postgresql dropping column defaults at migrate
再搜索一点,我发现了这个SO问题:Django implementation of default value in database,它导致了
_alter_field
方法的代码,其中存在以下注解:字符串
虽然最后一个是关于将现有的可空字段更改为不可空字段,但这似乎是Django处理
default
情况的方式: