序列化程序中的django rest框架更新方法,实例不会立即保存
Posted
技术标签:
【中文标题】序列化程序中的django rest框架更新方法,实例不会立即保存【英文标题】:django rest framework update method in serializer, instance is not saved immediately 【发布时间】:2019-03-18 09:00:55 【问题描述】:要更新的实例有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
当给方法一个 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 #"abc@email.com" is printed as celery output.
实例用instance.save()
保存,其中email
从abc@mail.com
更新为xyz@mail.com
,然后实例的id作为参数传递给shared_task
方法以发送邮件。但认为电子邮件似乎终于更新了。从send_activation_mail(user_id):
内部的user_id
获取的User
实例似乎没有更新,邮件发送到之前的email
。
【问题讨论】:
每次在打印电子邮件值之前使用instance.refresh_from_db()
,因为目前您没有检查电子邮件是否保存到数据库,您只需在模型实例上打印缓存的电子邮件
@KamilNiski 是正确的。即使您可以将 instance.email 传递给 send_activation_mail() 方法,而不是查询 shared_task
@KamilNiski 是的。该实例似乎尚未保存到数据库。调用保存后如何强制它立即保存?在整个update
方法执行之后,实例已经被保存。但不是instance.save(0
@Shameless 看起来您的问题不在您提供的代码中。我怀疑instance.__dict__.update(**validated_data)
会导致错误。现在我建议粘贴settings.py
并使用ipdb
和手动调试。可能我们没有足够的信息来解决这个问题。
【参考方案1】:
instance.save()
尚未提交到数据库。在此之前,已经调用了 celery 任务 send_activation_mail.delay(instance.id)
,导致获取的实例不是所需的更新实例。
所以为了克服这个问题,我们应该使用@transaction.atomic
和transaction.on_commit
即
<b>@transaction.atomic</b>
装饰器将在视图返回时提交事务,或者在视图引发异常时回滚。
<b>transaction.on_commit</b>
是在所有事务都成功提交后启动任务的回调。
<b>@987654321@</b>
在 Django 1.9 及更高版本中可用
【讨论】:
【参考方案2】:validated_data
和self.validated_data
一样吗?
因为我看到你使用它们是可交换的
【讨论】:
以上是关于序列化程序中的django rest框架更新方法,实例不会立即保存的主要内容,如果未能解决你的问题,请参考以下文章
Django Rest Framework,如何更新序列化程序中的嵌套值