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

Django中用Celery渲染邮件模板时遇TemplateDoesNotExist错误

Django Celery任务渲染模板时出现TemplateDoesNotExist错误

问题场景

开发论坛API时,通过类视图触发Celery异步任务发送邮箱验证邮件,任务内使用render_to_string渲染模板生成邮件内容。直接以普通函数调用任务逻辑时运行正常,但通过delay方法异步执行时,抛出TemplateDoesNotExist错误,且其他Celery任务可正常执行。


相关代码与配置

视图代码

class RequestEmailToConfirmAPIView(GenericAPIView):

    permission_classes = [IsAuthenticated, EmailIsNotConfirmed]
    success_message = 'The message has just been delivered.'
    serializer_class = DummySerializer

    def get(self, request):
        current_url = get_current_site(request, path='email-confirmation-result') 

        user = request.user
        token = EmailConfirmationToken.objects.create(user=user)

        send_confirmation_email.delay(
            template_name='email/confirm_email.txt', current_url=current_url,
            email=user.email, token_id=token.id, user_id=user.id
        )

        return Response(data={"message": self.success_message}, status=status.HTTP_201_CREATED)

Celery任务代码

@shared_task
def send_confirmation_email(template_name: str, current_url: str, email: str, token_id: int, user_id: int):
    """发送验证邮件"""
    data = {
        'current_site': str(current_url),
        'token_id': str(token_id),
        'user_id': str(user_id)
    }

    message = render_to_string(template_name, context=data)
    send_mail(
        subject='Пожалуйста, подтвердите почту',
        message=message,
        from_email='admin@ourweb.com',
        recipient_list=[email],
        fail_silently=True
    )

项目目录结构

├── backend
│   ├── celery_app.py
│   ├── core
│   │   └── settings.py
│   ├── forum
│   │   └── views.py
│   ├── templates
│   │   └── email
│   │       ├── confirm_email.txt
│   │       └── ...其他模板
│   └── web.env
├── docker-compose.yml
└── ...其他文件

Celery配置(celery_app.py)

from celery import Celery
from django.conf import settings
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')

app = Celery('backend.core')
app.config_from_object('django.conf:settings')
app.conf.broker_url = settings.CELERY_BROKER_URL
app.autodiscover_tasks()

Docker Compose中Celery Worker配置

celery-worker:
    restart: always
    build:
      context: ./backend
    entrypoint: /bin/sh
    command: -c "export PYTHONPATH=/backend:/backend/backend && celery -A backend.celery_app:app worker --loglevel=info"
    volumes:
      - .:/backend
    depends_on:
      - db
      - redis
      - backend
    env_file:
      - backend/web.env

错误栈

celery-worker               | django.template.exceptions.TemplateDoesNotExist: email/confirm_email.txt
celery-worker               | Traceback (most recent call last):
celery-worker               |   File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 451, in trace_task
celery-worker               |     R = retval = fun(*args, **kwargs)
celery-worker               |   File "/backend/backend/accounts/tasks.py", line 19, in send_confirmation_email
celery-worker               |     message = render_to_string(template_name, context=data)
celery-worker               |   File "/usr/local/lib/python3.11/site-packages/django/template/loader.py", line 61, in render_to_string
celery-worker               |     template = get_template(template_name, using=using)
celery-worker               |   File "/usr/local/lib/python3.11/site-packages/django/template/loader.py", line 19, in get_template
celery-worker               |     raise TemplateDoesNotExist(template_name, chain=chain)

排查与解决步骤

1. 验证Django模板路径配置

检查core/settings.py中的TEMPLATES配置,确保DIRS字段正确指向模板目录:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],  # 确保此处指向backend/templates
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

2. 修复Celery Worker的工作路径与启动命令

当前Worker的PYTHONPATH设置可能导致路径混乱,修改docker-compose.yml中的Worker配置:

celery-worker:
    restart: always
    build:
      context: ./backend
    command: celery -A celery_app:app worker --loglevel=info
    working_dir: /backend  # 明确指定工作目录为backend根目录
    volumes:
      - ./backend/:/backend  # 确保挂载目录正确
    depends_on:
      - db
      - redis
      - backend
    env_file:
      - backend/web.env

3. 确保Celery Worker初始化Django环境

在任务中显式初始化Django环境(避免Worker未自动加载配置):

@shared_task
def send_confirmation_email(template_name: str, current_url: str, email: str, token_id: int, user_id: int):
    import django
    from django.conf import settings

    if not settings.configured:
        django.setup()
    
    # 原有逻辑
    data = {
        'current_site': str(current_url),
        'token_id': str(token_id),
        'user_id': str(user_id)
    }
    message = render_to_string(template_name, context=data)
    send_mail(
        subject='Пожалуйста, подтвердите почту',
        message=message,
        from_email='admin@ourweb.com',
        recipient_list=[email],
        fail_silently=True
    )

4. 备选方案:在视图中预渲染模板

若以上方法无效,可在视图中先完成模板渲染,再将渲染后的字符串传递给Celery任务:

# 视图中修改
from django.template.loader import render_to_string

def get(self, request):
    current_url = get_current_site(request, path='email-confirmation-result') 
    user = request.user
    token = EmailConfirmationToken.objects.create(user=user)

    # 提前渲染模板
    message = render_to_string(
        'email/confirm_email.txt',
        context={
            'current_site': str(current_url),
            'token_id': str(token.id),
            'user_id': str(user.id)
        }
    )

    send_confirmation_email.delay(message=message, email=user.email)
    return Response(data={"message": self.success_message}, status=status.HTTP_201_CREATED)

修改任务:

@shared_task
def send_confirmation_email(message: str, email: str):
    send_mail(
        subject='Пожалуйста, подтвердите почту',
        message=message,
        from_email='admin@ourweb.com',
        recipient_list=[email],
        fail_silently=True
    )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:45:03