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

数据迁移触发查询致测试报错:profile_user.is_deleted列不存在

解决Django迁移中Celery任务触发导致的column does not exist测试错误

问题核心分析

你遇到的这个报错,本质是异步任务的执行时机和数据库schema变更不同步导致的:

  • 你的trigger_thumbnails_update迁移调用了Celery异步任务make_image_thumbnail.delay(),但在测试环境中,这个任务可能在添加is_deleted字段的迁移执行前就开始运行了。
  • 即使迁移顺序看起来是对的,Celery任务使用的是当前代码中的User模型(已经包含is_deleted字段),但此时数据库还没完成字段添加的迁移,查询时自然会找不到这个字段。

可行的解决方案

方案1:迁移中同步处理缩略图生成(最稳妥)

数据迁移场景下,尽量避免使用异步任务,直接同步执行缩略图生成逻辑,完全在数据库schema的上下文里操作:

def trigger_thumbnails_update(apps, schema_editor):
    """ Trigger thumbnails update for profile app """
    User = apps.get_model('profile', 'User')
    # 注意:必须使用apps.get_model获取迁移版本的模型,不能直接导入当前的User
    for user in User.objects.all():
        if user.photo:
            # 调用同步版本的生成函数,把原来Celery任务里的逻辑抽出来
            generate_thumbnail_sync(user.photo, user.pk)

# 抽离同步逻辑,避免异步依赖
def generate_thumbnail_sync(photo, user_pk):
    # 这里写原来make_image_thumbnail任务中的核心逻辑
    # 注意:如果需要操作模型,也要用apps.get_model获取,避免导入当前模型
    User = apps.get_model('profile', 'User')
    try:
        user = User.objects.get(pk=user_pk)
    except User.DoesNotExist:
        return
    # 生成缩略图并保存的逻辑...

这种方式完全不会有异步时序问题,迁移执行时数据库schema是确定的,查询不会出错。

方案2:调整迁移顺序,确保异步任务在schema变更后执行

如果一定要保留异步任务,你可以调整迁移的先后顺序:

  1. 把触发缩略图更新的迁移文件重命名(比如从0009_trigger_thumbnails_update改成0011_trigger_thumbnails_update)
  2. 修改它的dependencies,指向添加is_deleted字段的迁移:
    dependencies = [
        ('profile', '0010_auto_xxxxxx_xxxx'),  # 替换成你添加is_deleted字段的迁移文件名
    ]
    
  3. 同时修改添加is_deleted字段的迁移的dependencies,指向之前的基础迁移(比如0008_auto_20190611_2120)

这样迁移执行顺序就变成:基础迁移 → 添加字段 → 触发异步任务,此时数据库已经有了is_deleted字段,任务查询时就不会报错了。

方案3:修改Celery任务,避免查询不存在的字段

如果无法调整迁移顺序,你可以修改Celery任务,只查询需要的字段,避免触碰还未创建的is_deleted:

from django.apps import apps

def make_image_thumbnail(pk):
    # 使用apps.get_model动态获取模型,适配当前数据库schema
    User = apps.get_model('profile', 'User')
    try:
        # 只查询生成缩略图需要的字段,不要查询is_deleted
        user = User.objects.only('photo', 'pk').get(pk=pk)
    except User.DoesNotExist:
        return
    # 生成缩略图的逻辑...

通过only()指定查询字段,即使数据库里还没有is_deleted,也不会在查询语句中出现这个字段,自然不会触发报错。

测试环境额外配置

在pytest中,建议开启Celery的同步执行模式,确保任务在迁移完成后再执行:
在测试配置文件(比如pytest.ini或conftest.py)中添加:

import django
from django.conf import settings

def pytest_configure():
    settings.CELERY_TASK_ALWAYS_EAGER = True
    settings.CELERY_TASK_EAGER_PROPAGATES = True

这样所有Celery任务都会同步执行,完全避免异步时序问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:04:45