Django South 迁移未设置默认值

10

我使用south来迁移我的Django模型。然而,south存在一个令人不爽的bug。它不会在Postgres数据库中设置默认值。例如:

created_at = models.DateTimeField(default = datetime.now)
tag_id = models.PositiveIntegerField(default = 0)

South将这2个字段添加到数据库,但未能设置它们的默认值,需要手动完成。

有没有针对这个错误的补丁程序?

更新 我已经尝试使用 auto_now_add=True 设置默认日期,但仍未设置默认值。在字段中添加 null=True 会在由South生成的迁移脚本中添加一个 db.alter_column。但是,这只是删除了NOT NULL约束,没有添加默认值。整数字段同理。

3个回答

22

如果您正在使用自动生成的迁移文件:

./manage.py schemamigration app_name --auto

在实际应用迁移之前,您需要对迁移进行一些小的修改。进入生成的迁移文件(应该类似于app_name/migrations/000X__auto_add_field_foo.py),并查找参数:

keep_default=False

db.add_column 的调用中。只需将其更改为:

keep_default=True

Django现在会将你的默认值应用于实际模式,以及任何现有行。如果South默认生成此参数为True那就太好了,但没有这样的运气。您需要每次进行此编辑。


5
很遗憾,keep_default 在 South 0.8.1 中已被弃用。 - Pankrat

12

这不是一个bug,无论在南方还是其他地方。

我认为你对Django中默认值的工作原理存在困惑。Django一般不在数据库模式中设置默认值。当创建新实例时,它会直接在Python中应用这些默认值。您可以通过执行manage.py sqlall来验证这一点,并查看生成的SQL是否包含default属性。


2
如何在Postgres数据库中强制设置默认值。我有使用Django创建的直接与数据库协商的API。它们期望默认值已经设置好了。 - jerrymouse
5
您需要使用自定义的SQL语句来修改模式。您可以通过将SQL语句传递给db.execute在South中完成此操作。 - Daniel Roseman
3
即使Django试图阻止用户在模式层面上更改字段默认值,也并不意味着他们就不应该能够这样做。我已经在下面发布了一个实际的解决方案。 - galarant
2
当您向模型添加一些非空字段并指定默认值时,如果South不使用它来更新现有行,则会感到奇怪。看起来South允许违反约束条件。 - sunprophit

2
如之前所述,Django 中的默认机制是在模型类中实现的,并且与 South 迁移无关。
此外,自 South 0.8 版本以来, keep_default 标志已被弃用,并且不会将默认值添加到您的模型中。
为了解决这个问题,我会编写一个自定义迁移来添加默认值。您可以通过创建单独的 数据迁移 来实现这一点:
./manage.py datamigration your_app_name migration_name

并将以下行添加到“forwards”函数中:
orm.YourModel.objects.update(field_name = DEFAULT_VALUE)

另外,您可以修改原始迁移而不是创建新的迁移:
  1. no_dry_run = True添加到类本身(这样您就可以访问ORM)。
  2. orm.YourModel.objects.update(field_name = DEFAULT_VALUE)添加到forwards函数的末尾。
这样,您无需编写后退迁移,因为已经有了原始的删除列迁移。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接