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

Django中Project模型图片压缩Celery任务报错:无法找到实例

Django中Celery异步压缩图片触发Http404的解决方法

问题场景

我定义了如下Project模型:

class Project(models.Model):
    id = models.UUIDField(primary_key=True, unique=True, default=uuid4, editable=False)
    logo = models.ImageField(validators=[validate_image_size], blank=True, null=True, default=None)
    name = models.CharField(max_length=64)
    description = models.TextField()

    @transaction.atomic
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name

通过post_save信号触发Celery异步任务压缩logo字段:

@receiver(post_save, sender=Project)
def compress_project_logo(sender, instance, **kwargs):
    compress_image.apply_async((instance.id,))

对应的异步任务代码:

@shared_task
def compress_image(project_id):
    from api.models import Project
    project = get_object_or_404(Project, id=project_id)
    compressed_image = Image.open(project.logo)
    compressed_image = compressed_image.convert("RGB")
    compressed_image = ImageOps.exif_transpose(compressed_image)

    image_io = BytesIO()
    compressed_image.save(image_io, "JPEG", quality=70)
    project.logo = InMemoryUploadedFile(image_io, "ImageField", project.logo.file.name, "image/jpeg", sys.getsizeof(image_io), None)
    project.save()

但在Django admin中保存Project模型时,Celery任务抛出如下错误:

Traceback (most recent call last):
2023-02-28 10:27:45   

File "/usr/local/lib/python3.8/site-packages/celery/app/trace.py", line 450, in trace_task
  R = retval = fun(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/celery/app/trace.py", line 731, in __protected_call__
  return self.run(*args, **kwargs)
File "/code/api/tasks/compress.py", line 14, in compress_image
  project = get_object_or_404(Project, id=project_id)
File "/usr/local/lib/python3.8/site-packages/rest_framework/generics.py", line 19, in get_object_or_404
  return _get_object_or_404(queryset, *filter_args, **filter_kwargs)
File "/usr/local/lib/python3.8/site-packages/django/shortcuts.py", line 78, in get_object_or_404
  raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
django.http.response.Http404: No Project matches the given query.

问题核心原因

这是事务隔离机制导致的:Django admin的保存操作和自定义的save方法都使用了transaction.atomic,当post_save信号触发时,事务尚未提交到数据库,Celery异步任务立即执行时,无法查询到这条刚创建的Project记录,从而抛出404异常。

解决方法

方法1:用transaction.on_commit延迟任务执行

将信号接收器中的任务调用包裹在transaction.on_commit内,确保事务完全提交后再触发Celery任务:

from django.db import transaction

@receiver(post_save, sender=Project)
def compress_project_logo(sender, instance, **kwargs):
    transaction.on_commit(lambda: compress_image.apply_async((instance.id,)))

此方法能兼容新增和更新场景,确保任务执行时数据库中已存在目标记录。

方法2:移除save方法中的冗余事务装饰器

当前save方法中的@transaction.atomic是多余的——Django默认会在模型save操作时自动开启事务,移除该装饰器后,保存完成事务立即提交,信号触发的任务就能正常查询到数据:

# 修改后的Project模型save方法
def save(self, *args, **kwargs):
    super().save(*args, **kwargs)

额外优化建议

  • 在异步任务中增加异常捕获,避免因logo为空或记录不存在导致任务失败:
@shared_task
def compress_image(project_id):
    from api.models import Project
    try:
        project = Project.objects.get(id=project_id)
        if not project.logo:
            return
        # 图片压缩逻辑...
        project.save()
    except Project.DoesNotExist:
        return
  • 确认Celery worker与Django使用同一数据库配置,避免跨数据库查询问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 11:22:35