Celery任务数据库查询返回None/DoesNotExist问题求助
问题
在Django应用中使用Celery任务时,数据库查询出现异常:
email_on_assign_reviewer任务遍历reviewerlist查询Reviewer实例时返回None,但视图的perform_create方法中相同查询能正常获取实例,且序列化器已创建对应Reviewer实例。- 部分任务查询
Submission时抛出DoesNotExist异常。
相关代码如下:
任务代码
@shared_task def email_on_assign_reviewer(submission, reviewerlist): """ Send an email to the Reviewer when they are assigned to review """ print(submission) # 输出正常 print(reviewerlist) # 能完美打印审核员ID列表 submission = Submission.objects.get(id=submission) print(submission) # 能完美打印投稿信息 context = {"some": "context"} for id in reviewerlist: reviewer = Reviewer.objects.filter(id=id).first() print(reviewer) # 这里返回None if reviewer: context['reviewer_name'] = reviewer.user.first_name utils.sendEmail( context, template="review_assign.html", to=[reviewer.user.email] )
视图代码
def perform_create(self, serializer): submission = Submission.objects.filter(id=self.kwargs['submission_pk']).first() *SOME LOGIC* data = serializer.save() for i in reviewerlist: print(Reviewer.objects.filter(id=i).first()) # 这里能完美打印审核员信息 tasks.email_on_assign_reviewer.delay(submission.id, reviewerlist)
序列化器代码
def create(self, validated_data): submission_id = self.context['submission_id'] user_ids = validated_data.pop('user_ids', []) existing_profile_ids = Somequery.objects.all() reviewers_to_create = [] for user_id in user_ids: if user_id not in existing_profile_ids: reviewer = Reviewer.objects.create(submission_id=submission_id, user_id=user_id, ) reviewers_to_create.append(reviewer.pk) return reviewers_to_create
解决方案
1. 事务未提交导致Celery查询不到数据
视图的perform_create方法中,序列化器创建Reviewer实例后,当前请求的事务可能还未提交就调用了Celery任务。Celery任务独立运行,此时数据库中还没有新创建的Reviewer记录。
- 解决办法:
使用Django的transaction.on_commit延迟发送Celery任务,确保事务提交后再执行任务:from django.db import transaction # 在perform_create中替换原任务调用 transaction.on_commit(lambda: tasks.email_on_assign_reviewer.delay(submission.id, reviewerlist))
2. 数据库连接隔离级别问题
如果数据库使用了READ COMMITTED以外的隔离级别,Celery任务可能无法读取到未提交的事务数据。
- 解决办法:
确保Django数据库配置的隔离级别为READ COMMITTED(默认配置),在settings.py中:DATABASES = { 'default': { # ... 其他配置 'OPTIONS': { 'isolation_level': 'read committed', }, } }
3. Submission查询异常处理
部分任务中Submission.objects.get(id=submission)抛出DoesNotExist,可能是任务执行时数据已被删除或ID无效。
- 解决办法:
用filter(...).first()替代get()避免抛出异常,增加容错:submission = Submission.objects.filter(id=submission).first() if not submission: return # 或记录日志后终止任务
4. 确认reviewerlist传递的是正确ID
检查视图中reviewerlist的来源是否为序列化器返回的reviewers_to_create(即Reviewer的ID),而非原始的user_ids,避免传递错误的ID导致查询不到数据。
内容的提问来源于stack exchange,提问作者Ayatoo
相关产品推荐
相关产品推荐

