Django Rest Framework更新方法在序列化程序中,实例不会立即保存 [英] django rest framework update method in serializer, instance is not saved immediately

查看:118
本文介绍了Django Rest Framework更新方法在序列化程序中,实例不会立即保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要更新的实例具有 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(),其中电子邮件 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.comand 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆