我尝试创建一个可调用的默认字段:
from datetime import date, timedelta
from django.db import models
class Preferences(models.Model):
expiration_days = models.IntegerField(default=30)
... other db settings here ...
class ImportantBusinessObject(models.Model):
expiration_date = models.DateField(default=get_default_expiration_date)
def get_default_expiration_date():
expiration_days = Preferences.objects.first().expiration_days
return date.today() + timedelta(days=expiration_days)
这个想法是在db中存储了一组全局首选项,这会影响其他模型对象的默认值。
在为Preferences
课程添加另一个字段之前,一切都很好并且花花公子。然后,在构建db时(例如,在运行测试时),添加expiration_date
字段的迁移最终会在新迁移添加另一个首选项字段之前执行。在调用get_default_expiration_date()
期间,Preferences对象是最新版本,但是DB没有获得最新的迁移,我收到column preferences.new_preference does not exist
错误。
解决这个问题的最佳方法是什么?
现在我在测试过程中禁用迁移作为一种解决方法,但我想知道是否还有另一种方式。
我尝试从get_default_expiration_date()
内的app注册表中抓取该模型,但它仍然是最新版本,而不是{{1}中给出的版本化版本函数。
我还尝试在try / except块中包装获取migrations.RunPython
对象的行,但db最终处于回滚状态,我无法继续。
其他位:
Preferences
类实际上是使用django-solo的db单例。更新:明确操作顺序
以下是发生事件的时间表:
Preferences
:初始偏好设置,包括preferences/migrations/initial_0001.py
expiration_days
:初始业务对象,取决于business/migrations/initial_0001.py
preferences 0001
:向preferences/migrations/add_pref_0002.py
一旦我在步骤#3中定义了迁移,事情就会开始中断,因为在运行时从步骤#2添加迁移时,会调用Preferences
来引发错误。从下面关于更新依赖关系的注释线程,我的观点是,为了做到这一点,每次我添加新的首选项迁移时,我都需要更新先前定义的get_default_expiration_date
(以及其他行为相似的其他人)的依赖关系)。希望这能澄清一下情况。
答案 0 :(得分:3)
您似乎遇到了文档here中讨论的问题:
因为序列化任意Python代码是不可能的,所以这些历史模型将没有您定义的任何自定义方法。
这通常出现在创建模型实例的数据迁移的上下文中。如果您在迁移期间没有创建任何实例,那么get_default_expiration_date()
永远不会被执行,并且您不会遇到问题。 (我不确定在你的情况下做什么,也许与django-solo或你正在使用的其他套餐有关?)
我认为在这种情况下最简单的解决方案是确保默认函数仅引用它们所需的字段,这样他们就不会生成对可能尚不存在的SQL列的引用。当你得到像你一样的整个对象时,它会尝试获取所有字段,并查看当前(非历史)模型定义以查看这些字段是什么。
如果您使用values()
(或only()
),生成的SQL将仅引用您指定的字段:
def get_default_expiration_date():
expiration_days = Preferences.objects.values("expiration_days")[0]["expiration_days"]