You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django自定义迁移未生效:调用save()未更新status字段求助

问题排查与解决方案

首先,你踩的这个坑其实是Django迁移系统的一个常见误区:迁移中通过apps.get_model获取的模型是历史快照版本,不是你当前models.py里带自定义save()方法的那个SOS模型。

为什么会这样?

Django迁移的核心设计是保证可重复性——每个迁移文件都会基于当时的模型结构生成快照。当你在迁移里调用apps.get_model('sos', 'SOS')时,拿到的是没有重写save()的基础Model类,所以执行sos.save()只会跑默认的保存逻辑,完全不会触发你写的状态计算代码。这就解释了为什么迁移执行极快(根本没处理业务逻辑),且所有对象的status还是默认值"New"。

快速验证这个结论

你可以在迁移的set_status函数里加一行打印,看看当前SOS模型的save方法是不是默认的:

def set_status(apps, schema_editor):
    SOS = apps.get_model('sos', 'SOS')
    print(SOS.save)  # 执行迁移时会看到输出是django.db.models.Model.save,不是你自定义的方法
    for sos in SOS.objects.all():
        sos.save()

执行迁移后,打印结果会直接验证这个问题。

两种靠谱的解决办法

方式一:在迁移里直接实现状态计算逻辑(推荐)

既然不能依赖模型的自定义save方法,那就把save里的逻辑直接搬到迁移函数里,完全基于历史快照模型操作:

def set_status(apps, schema_editor):
    SOS = apps.get_model('sos', 'SOS')
    # 别忘了获取History模型的历史快照(替换成你的History模型实际名称)
    History = apps.get_model('sos', 'History')
    for sos in SOS.objects.all():
        # 完全复刻你save方法里的逻辑
        history_queryset = History.objects.filter(sos=sos)
        if history_queryset.exists():
            latest_history = history_queryset.get(version=sos.latest_version)
            sos.status = latest_history.status
        else:
            sos.status = "New"
        # 用update_fields只更新status字段,更高效
        sos.save(update_fields=['status'])

这种方式完全符合Django迁移的设计原则,不管后续模型怎么改,这个迁移都能稳定执行。

方式二:直接导入当前模型(不推荐,谨慎使用)

如果你非要用当前模型的save方法,可以直接导入,但强烈不建议——因为这会破坏迁移的可重复性,后续如果模型的save方法或字段结构变化,这个旧迁移可能直接报错:

def set_status(apps, schema_editor):
    from sos.models import SOS  # 跳过迁移快照,直接用当前模型
    for sos in SOS.objects.all():
        sos.save()

这种方式虽然能快速解决当前问题,但埋下了后续迁移失败的隐患,除非你能保证这个模型的save逻辑永远不变,否则别用。

额外优化:批量处理提升速度

处理300+条数据时,循环单个save效率很低,换成bulk_update能大幅减少数据库请求:

def set_status(apps, schema_editor):
    SOS = apps.get_model('sos', 'SOS')
    History = apps.get_model('sos', 'History')
    update_list = []
    for sos in SOS.objects.all():
        history_queryset = History.objects.filter(sos=sos)
        if history_queryset.exists():
            latest_history = history_queryset.get(version=sos.latest_version)
            sos.status = latest_history.status
        else:
            sos.status = "New"
        update_list.append(sos)
    # 批量更新status字段
    SOS.objects.bulk_update(update_list, ['status'])

这样迁移执行速度会快很多,也更符合数据库操作的最佳实践。

内容的提问来源于stack exchange,提问作者Nealon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:12:19