我想用芹菜发送重置密码的电子邮件。我尝试重写类djoser.views.UserViewSet
的reset_password
方法:
class CustomUserViewSet(UserViewSet):
@action(["post"], detail=False)
def reset_password(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.get_user()
if user:
send_reset_password_email.delay(
self.request,
{'user': user},
[get_user_email(user)]
)
return Response(status=status.HTTP_200_OK)
但是我得到一个错误:
Traceback (most recent call last):
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 39, in _reraise_errors
yield
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 210, in dumps
payload = encoder(data)
File "C:Devrich-peachvenvlibsite-packageskombuutilsjson.py", line 68, in dumps
return _dumps(s, cls=cls or _default_encoder,
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjson__init__.py", line 238, in dumps
**kw).encode(obj)
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjsonencoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjsonencoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "C:Devrich-peachvenvlibsite-packageskombuutilsjson.py", line 58, in default
return super().default(o)
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjsonencoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Request is not JSON serializable
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:Devrich-peachvenvlibsite-packagesdjangocorehandlersexception.py", line 55, in inner
response = get_response(request)
File "C:Devrich-peachvenvlibsite-packagesdjangocorehandlersbase.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:Devrich-peachvenvlibsite-packagesdjangoviewsdecoratorscsrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 480, in raise_uncaught_exception
raise exc
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "C:Devrich-peachbackendapiviews.py", line 51, in reset_password
send_reset_password_email.delay(
File "C:Devrich-peachvenvlibsite-packagesceleryapptask.py", line 425, in delay
return self.apply_async(args, kwargs)
File "C:Devrich-peachvenvlibsite-packagesceleryapptask.py", line 575, in apply_async
return app.send_task(
File "C:Devrich-peachvenvlibsite-packagesceleryappbase.py", line 788, in send_task
amqp.send_task_message(P, name, message, **options)
File "C:Devrich-peachvenvlibsite-packagesceleryappamqp.py", line 510, in send_task_message
ret = producer.publish(
File "C:Devrich-peachvenvlibsite-packageskombumessaging.py", line 166, in publish
body, content_type, content_encoding = self._prepare(
File "C:Devrich-peachvenvlibsite-packageskombumessaging.py", line 254, in _prepare
body) = dumps(body, serializer=serializer)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 209, in dumps
with _reraise_errors(EncodeError):
File "C:Userslev_kAppDataLocalProgramsPythonPython310libcontextlib.py", line 153, in __exit__
self.gen.throw(typ, value, traceback)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 43, in _reraise_errors
reraise(wrapper, wrapper(exc), sys.exc_info()[2])
File "C:Devrich-peachvenvlibsite-packageskombuexceptions.py", line 21, in reraise
raise value.with_traceback(tb)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 39, in _reraise_errors
yield
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 210, in dumps
payload = encoder(data)
File "C:Devrich-peachvenvlibsite-packageskombuutilsjson.py", line 68, in dumps
return _dumps(s, cls=cls or _default_encoder,
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjson__init__.py", line 238, in dumps
**kw).encode(obj)
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjsonencoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjsonencoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "C:Devrich-peachvenvlibsite-packageskombuutilsjson.py", line 58, in default
return super().default(o)
File "C:Userslev_kAppDataLocalProgramsPythonPython310libjsonencoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
kombu.exceptions.EncodeError: Object of type Request is not JSON serializable
芹菜任务:
@app.task(bind=True, default_retry_delay=5 * 60)
def send_reset_password_email(self, request, context, email):
try:
PasswordResetEmail(request, context).send(email)
except Exception as exc:
raise self.retry(exc=exc, countdown=60)
我已经尝试过的:
我试图将任务的序列化器更改为'pickle'
:
@app.task(bind=True, default_retry_delay=5 * 60, serializer='pickle')
但是我得到一个新的错误:
Traceback (most recent call last):
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 39, in _reraise_errors
yield
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 210, in dumps
payload = encoder(data)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 334, in pickle_dumps
return dumper(obj, protocol=pickle_protocol)
TypeError: cannot pickle '_io.BufferedReader' object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:Devrich-peachvenvlibsite-packagesdjangocorehandlersexception.py", line 55, in inner
response = get_response(request)
File "C:Devrich-peachvenvlibsite-packagesdjangocorehandlersbase.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:Devrich-peachvenvlibsite-packagesdjangoviewsdecoratorscsrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 480, in raise_uncaught_exception
raise exc
File "C:Devrich-peachvenvlibsite-packagesrest_frameworkviews.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "C:Devrich-peachbackendapiviews.py", line 51, in reset_password
send_reset_password_email.delay(
File "C:Devrich-peachvenvlibsite-packagesceleryapptask.py", line 425, in delay
return self.apply_async(args, kwargs)
File "C:Devrich-peachvenvlibsite-packagesceleryapptask.py", line 575, in apply_async
return app.send_task(
File "C:Devrich-peachvenvlibsite-packagesceleryappbase.py", line 788, in send_task
amqp.send_task_message(P, name, message, **options)
File "C:Devrich-peachvenvlibsite-packagesceleryappamqp.py", line 510, in send_task_message
ret = producer.publish(
File "C:Devrich-peachvenvlibsite-packageskombumessaging.py", line 166, in publish
body, content_type, content_encoding = self._prepare(
File "C:Devrich-peachvenvlibsite-packageskombumessaging.py", line 254, in _prepare
body) = dumps(body, serializer=serializer)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 209, in dumps
with _reraise_errors(EncodeError):
File "C:Userslev_kAppDataLocalProgramsPythonPython310libcontextlib.py", line 153, in __exit__
self.gen.throw(typ, value, traceback)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 43, in _reraise_errors
reraise(wrapper, wrapper(exc), sys.exc_info()[2])
File "C:Devrich-peachvenvlibsite-packageskombuexceptions.py", line 21, in reraise
raise value.with_traceback(tb)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 39, in _reraise_errors
yield
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 210, in dumps
payload = encoder(data)
File "C:Devrich-peachvenvlibsite-packageskombuserialization.py", line 334, in pickle_dumps
return dumper(obj, protocol=pickle_protocol)
kombu.exceptions.EncodeError: cannot pickle '_io.BufferedReader' object
我该如何解决这个问题?
不然我怎么做呢?
问题解决了!
我将必要的字段传递给上下文而不是请求,而不是user - user.id:
@action(['post'], detail=False)
def reset_password(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.get_user()
if user:
send_reset_password_email.delay(
{
'user_id': user.id,
'domain': request.get_host(),
'protocol': 'https' if request.is_secure() else 'http',
'site_name': request.get_host()
},
[get_user_email(user)]
)
return Response(status=status.HTTP_200_OK)
这是有效的,因为如果你不发送请求到Password Reset E-mail, Djoser在上下文中搜索必要的字段:
class BaseEmailMessage(mail.EmailMultiAlternatives, ContextMixin):
def get_context_data(self, **kwargs):
ctx = super(BaseEmailMessage, self).get_context_data(**kwargs)
context = dict(ctx, **self.context)
if self.request:
site = get_current_site(self.request)
domain = context.get('domain') or (
getattr(settings, 'DOMAIN', '') or site.domain
)
protocol = context.get('protocol') or (
'https' if self.request.is_secure() else 'http'
)
site_name = context.get('site_name') or (
getattr(settings, 'SITE_NAME', '') or site.name
)
user = context.get('user') or self.request.user
else:
domain = context.get('domain') or getattr(settings, 'DOMAIN', '')
protocol = context.get('protocol') or 'http'
site_name = context.get('site_name') or getattr(
settings, 'SITE_NAME', ''
)
user = context.get('user')
context.update({
'domain': domain,
'protocol': protocol,
'site_name': site_name,
'user': user
})
return context
在任务中,我通过id获取用户,我将其传递给context:
@app.task(bind=True, default_retry_delay=5 * 60)
def send_reset_password_email(self, context, email):
try:
context['user'] = CustomUser.objects.get(id=context.get('user_id'))
PasswordResetEmail(context=context).send(email)
except Exception as exc:
raise self.retry(exc=exc, countdown=60)