Django Celery отправить электронное письмо электронной почты не работает

Я изучаю сельдерей. На моем веб-сайте я позволяю людям регистрировать учетную запись. Как только они создадут новую учетную запись, она автоматически отправит электронное письмо активации на свой адрес электронной почты пользователя.

Все работает хорошо, но теперь я хочу использовать Сельдерей для отправки асинхронного сообщения.

Я использую RabbitMQ в качестве брокера, версию 3.1.5 и Celery 3.1.7 (последняя версия), так как говорят, что этой версии не требуется djcelery. Так что мне нужно всего лишь установить сельдерей.

Я следил за инструкцией в качестве сельдерея на его веб-сайте, Конфигурируйте мой django.

proj
  --proj/celery.py

Вот мой celery.py:

from __future__ import absolute_import

import os

from celery import Celery

from django.conf import settings

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

app = Celery('proj')

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

@app.task(bind=True)
def debug_task(self):
    print('Request:{0!r}'.format(self.request))

И это tasks.py, который я вложил в папку своего приложения:

proj
 ---proj/celery.py
 ---app/tasks.py

tasks.py

from __future__ import absolute_import

from celery.decorators import task

@task()
def user_send_activation_email(user):
    user.send_activation_email()

Я добавил функцию send_activation_email к пользовательским моделям, поэтому пользователь может отправить электронное письмо.

Это мой views.py:

from django.shortcuts import render_to_response, redirect,render
from django.conf import settings
from django.http import HttpResponse,HttpResponseRedirect,Http404
from django.template import RequestContext
from app.accounts.forms import SignupForm
from django.contrib.auth import get_user_model
from app.sns_utils import generate_sha1 
from app.tasks import user_send_activation_email 

def signup(request):
    if request.method=='POST':
        form=SignupForm(data=request.POST)
        if form.is_valid():
            UserModel=get_user_model()
            username = form.cleaned_data['username']
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
             user=UserModel.objects.create_user(username=username,email=email,password=password)
            user.activation_key = generate_sha1(username)
            user.save()
            user_send_activation_email.delay(user=user)


            return redirect('/')

И вот как я настроил сельдерей в settings.py:

BROKER_URL = 'amqp://guest:[email protected]:5672//'

CELERY_RESULT_BACKEND = 'amqp://guest:[email protected]:5672//'

CELERY_TASK_SERIALIZER = 'json'

все просто следует за сельдереем, о котором говорит его сайт.

Как только я manage.py runserver, на странице регистрации я зарегистрирую новую учетную запись с именем пользователя vmuser630, и она показывает эту ошибку:

EncodeError at /accounts/signup/
<MyUser: vmuser630> is not JSON serializable
Request Method: POST
Request URL:    http://localhost:8000/accounts/signup/
Django Version: 1.6
Exception Type: EncodeError
Exception Value:    
<MyUser: vmuser630> is not JSON serializable
Exception Location: C:\Python33\lib\json\encoder.py in default, line 173
Python Executable:  C:\Python33\python.exe
Python Version: 3.3.2

Если я удалю это из settings.py:

CELERY_TASK_SERIALIZER = 'json'

и повторите попытку manage.py runserver, я просто перенаправлен на страницу '/'. Новая учетная запись находится в базе данных, но я не получил адрес активации.

Похоже, что задача отправки электронной почты только что была передана, ничего не произошло.

Когда я меняю функцию отправки электронной почты на:

user.send_activation_email()

Это означает, что я не являюсь пользователем сельдерея, он работает, я могу получить адрес активации.

Почему он показывает ошибку не сериализуемую JSON?

Ответ 1

Сельдерей должен сериализовать аргументы для задачи. Здесь user не является сериализуемым, но вы можете заменить его своим идентификатором:

В tasks.py:

from __future__ import absolute_import

from celery.decorators import task
from django.contrib.auth import get_user_model

@task()
def user_send_activation_email(user_id):
    user = get_user_model().objects.get(pk=user_id)
    user.send_activation_email()

Затем вызовите его из views.py, используя:

user_send_activation_email.delay(user_id=user.pk)

Ответ 2

см. setting-task_serializer, вы можете установить CELERY_TASK_SERIALIZER = 'pickle' в celery conf.

Ответ 3

Сельдерей может сериализовать в строки JSON, Unicode, float, boolean, словари и списки. Похоже, он пытается и не выполняет сериализацию объекта MyUser.

Вам может быть интересно использовать django-post_office для асинхронной отправки по электронной почте.