Django Rest Framework更新方法在序列化器中,实例不会立即保存

时间:2018-10-13 08:53:16

标签: django django-rest-framework celery

要更新的实例具有instance.email=abc@mail.com

要更新或更改为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

当我使用celery向用户发送电子邮件时,给该方法的user_id为:

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()保存,其中emailabc@mail.com更新为xyz@mail.com,然后实例的ID作为参数传递给{{1} }方法来发送邮件。但是以为电子邮件似乎终于更新了。从shared_task内部的User获得的user_id实例似乎尚未更新,邮件已发送到先前的send_activation_mail(user_id):

2 个答案:

答案 0 :(得分:0)

validated_dataself.validated_data相同吗?

因为我发现您可以互换使用它们

答案 1 :(得分:0)

instance.save()尚未提交到数据库。在此之前,芹菜任务send_activation_mail.delay(instance.id)已被调用,导致获取的是比所需的更新实例更早的实例。

因此,要克服这一点,我们应该使用@transaction.atomictransaction.on_commit,即

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.on_commit是在成功提交所有事务后启动任务的回调。

  

on_commit在Django 1.9及更高版本中可用