Skip to main content
 首页 » 编程设计

python之使用查询数据库的默认字段函数迁移时出现 Django 错误

2024年08月23日30jillzhang

我正在尝试创建一个像这样可调用的默认字段:

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) 

这个想法是在数据库中存储了一组全局首选项,这会影响其他模型对象的默认值。

在将另一个字段添加到 Preferences 之前,一切都很好。类(class)。然后,在构建数据库时(例如,在运行测试时),添加 expiration_date 的迁移字段在新迁移添加另一个首选项字段之前结束执行。在通话期间 get_default_expiration_date() ,Preferences 对象是最新版本,但是数据库还没有得到最新的迁移,我得到一个 column preferences.new_preference does not exist错误。

解决这个问题的最佳方法是什么?

目前我正在测试期间禁用迁移作为解决方法,但我想知道是否还有其他方法。

我尝试从 get_default_expiration_date() 中的应用注册表中获取模型,但它仍然是最新版本,而不是您在 migrations.RunPython 中提供的版本版本。功能。

我也试过包装获取 Preferences 的行try/except block 中的对象,但数据库最终处于回滚状态,我无法继续。

其他位:

  • 我正在使用 Django 1.8
  • 在我的实际应用中,Preferences类实际上是一个使用 django-solo 的数据库单例。

更新:阐明操作顺序

以下是正在发生的事情的时间表:

  1. preferences/migrations/initial_0001.py :初始偏好,包括expiration_days
  2. business/migrations/initial_0001.py : 初始业务对象,取决于 preferences 0001
  3. preferences/migrations/add_pref_0002.py : 添加一个新字段到 Preferences

一旦我在步骤 #3 中定义了迁移,事情就开始中断了,因为在运行以添加来自步骤 #2 的迁移时,get_default_expiration_date被调用会抛出错误。从下面关于更新依赖项的评论线程中,我的观点是,为了做到这一点,每次添加新的首选项迁移时,我都需要更新先前定义的 business/migrations/initial_0001.py 的依赖项。 (以及任何其他行为相似的人)。希望这能稍微澄清一下情况。

请您参考如下方法:

您似乎遇到了文档 here 中讨论的问题:

Because it’s impossible to serialize arbitrary Python code, these historical models will not have any custom methods that you have defined.

这通常出现在创建模型实例的数据迁移的上下文中。如果您在迁移期间没有创建任何实例,那么 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"]