djangorest框架更新序列化器中的方法,实例不会立即保存

2024-01-11

要更新的实例有[email protected] /cdn-cgi/l/email-protection.

电子邮件要更新或更改为[email protected] /cdn-cgi/l/email-protection

UserUpdateSerializer的更新方法。

def update(self, instance, validated_data):
        email_updated=False
        email = self.validated_data["email"]
        print(instance.email) #[email protected] /cdn-cgi/l/email-protection
        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) #[email protected] /cdn-cgi/l/email-protection
        if email_updated:
            task_send_activation_mail.delay(instance.id)#this one here
        print(instance.email) #[email protected] /cdn-cgi/l/email-protection
        return instance

当向方法提供 user_id 时,我使用 celery 向用户发送电子邮件,如下所示:

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 #"[email protected] /cdn-cgi/l/email-protection" is printed as celery output.

该实例保存为instance.save(), where email更新自[email protected] /cdn-cgi/l/email-protection to [email protected] /cdn-cgi/l/email-protection然后实例的 id 作为参数传递给shared_task发送邮件的方法。但认为电子邮件似乎终于更新了。这User实例获得自user_id在 - 的里面send_activation_mail(user_id):好像还没有更新,邮件已发送至上一个email.


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

所以为了克服这个问题我们应该使用@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="[email protected] /cdn-cgi/l/email-protection")
    transaction.on_commit(lambda: my_task.delay(user.pk))
  

@transaction.atomic装饰器将在视图返回时提交事务,或者在视图引发异常时回滚。

transaction.on_commit是在所有事务均已成功提交后启动任务的回调。

on_commit https://docs.djangoproject.com/en/2.1/topics/db/transactions/#performing-actions-after-commit适用于 Django 1.9 及以上版本

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

djangorest框架更新序列化器中的方法,实例不会立即保存 的相关文章

随机推荐