要更新的实例具有 instance.email=abc@mail 。
要发送的电子邮件已更新或更改为 xyz@mail
email to be updated or changed to xyz@mail
UserUpdateSerializer 的更新方法。
def update(self, instance, validated_data): email_updated=False email = self.validated_data["email"] print(instance.email) #abc@email if email!=instance.email: if User.objects.filter(email=email).exists(): raise serializers.ValidationError("email is not available") else: email_updated=True instance.__dict__.update(**validated_data) instance.save() # instance is saved. print(instance.email) #xyz@email if email_updated: task_send_activation_mail.delay(instance.id)#this one here print(instance.email) #xyz@email return instance我正在使用芹菜向其发送电子邮件用户,当为该方法赋予user_id时:
I am using celery to send an email to the user when given a user_id to the method as:
from `celery` import shared_task @shared_task def send_activation_mail(user_id): from project.models import User user = User.objects.get(pk=user_id) subject = 'Activate Your '+DOMAIN_SHORT_NAME+' Account' message = get_template('registration/account_activation_email.html').render({ 'domain_url': DOMAIN_URL, 'domain': DOMAIN, 'domain_short_name': DOMAIN_SHORT_NAME, 'domain_full_name': DOMAIN_FULL_NAME, 'domain_email': DOMAIN_EMAIL, 'domain_support_email': DOMAIN_SUPPORT_EMAIL, 'domain_support_url': DOMAIN_SUPPORT_URL, 'mobile_support': MOBILE_SUPPORT, 'user': user, 'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(), 'token': account_activation_token.make_token(user), }) user.email_user(subject, DOMAIN_FULL_NAME +' ', html_message=message) return user.email #"abc@email" is printed as celery output.实例通过 instance.save(),其中电子邮件从 abc@mail 更新为 xyz @ mail。 com ,然后实例的ID作为参数传递给 shared_task 方法以发送邮件。但是以为电子邮件似乎终于更新了。从 send_activation_mail(user_id)内的 user_id 获得的 User 实例:似乎尚未更新,并且邮件已发送到以前的电子邮件。
The instance is saved with instance.save(), where email is updated from abc@mail to xyz@mailand then the instance's id is passed as a parameter to a shared_task method to send a mail. But thought the email appears updated finally. The User instance obtained from the user_id inside the send_activation_mail(user_id): appears to have not updated and the mail is sent to the previous email.
推荐答案instance.save()尚未提交到数据库。在此之前,调用了celery任务 send_activation_mail.delay(instance.id)导致获取的实例比所需的更新实例更早。
The instance.save() hasn't committed to the database yet. And before that the celery task send_activation_mail.delay(instance.id) has been called resulting in the getting the previous instance than the required updated instance.
因此,要克服这一点,我们应该使用 @ transaction.atomic 和 transaction.on_commit 即,
So to overcome this we should be using @transaction.atomic and transaction.on_commit i.e,
from django.db import transaction @transaction.atomic def myFunction(): user = User.objects.get(pk=1).update(email="xyz@email") transaction.on_commit(lambda: my_task.delay(user.pk))@ transaction.atomic 装饰器将提交事务当视图返回时返回,或在视图引发异常时回滚。
@transaction.atomic decorator will commit the transaction when the view returns, or roll back if the view raises an exception.
transaction.on_commit 是在成功完成所有事务后启动任务的回调。
transaction.on_commit is a callback to launch a task once all transactions have been committed successfully.
on_commit 在Django 1.9及更高版本中可用
on_commit is available in Django 1.9 and above
更多推荐
Django Rest Framework更新方法在序列化程序中,实例不会立即保存
发布评论