Django Rest Framework更新方法在序列化程序中,实例不会立即保存 [英] django rest framework update method in serializer, instance is not saved immediately
问题描述
要更新的实例具有 instance.email=abc@mail.com
。
要发送的电子邮件已更新或更改为 xyz@mail.com
email to be updated or changed to xyz@mail.com
UserUpdateSerializer
的更新方法。
def update(self, instance, validated_data):
email_updated=False
email = self.validated_data["email"]
print(instance.email) #abc@email.com
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.com
if email_updated:
task_send_activation_mail.delay(instance.id)#this one here
print(instance.email) #xyz@email.com
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.com" is printed as celery output.
实例通过 instance.save()$ c $保存c>,其中
电子邮件
从 abc@mail.com
更新为 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.com
to xyz@mail.com
and 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.com")
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.
< a href = https://docs.djangoproject.com/en/2.1/topics/db/transactio ns /#performing-actions-after-commit rel = nofollow noreferrer> on_commit
在Django 1.9及更高版本中可用
on_commit
is available in Django 1.9 and above
这篇关于Django Rest Framework更新方法在序列化程序中,实例不会立即保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!