首页 > 解决方案 > 无法在 Django UpdateView form_valid 中动态保存 user.is_active 或信号

问题描述

我有两个模型,User(扩展Abstract User和继承is_active字段)并Supervision使用通用外键连接到用户。当我们保存 Supervision 实例时,代码必须检查suspendedSupervision 实例上的字段并更新user.is_active为相反。我无法保存保存用户实例,因为它恢复为 True 并保存两次。这是我的代码form_valid()

suspension, created = Suspension.objects.get_or_create(
            content_type = ContentType.objects.get(app_label="myapp", model="suspension"),
            object_id = self.kwargs['pk'],
        )
suspension.reason = form.cleaned_data['reason']
suspension.suspended = form.cleaned_data['suspended']
suspension.save()
user = suspension.content_object
user.is_active = False if suspension.suspended else True
user.save()
return super().form_valid(form)

这是我的信号:

@receiver(post_save, sender=Suspension, weak=False, dispatch_uid=uuid.uuid4())
def suspend_unsuspend_user(sender, instance, **kwargs):
    from userprofile.models import User
    if isinstance(instance.content_object, User):
        user = instance.content_object
        user.is_active = instance.suspended 
        user.save()

更新:覆盖Suspension模型上的 save() 以更新用户实例

def save(self, *args, **kwargs):
    from userprofile.models import User
    if isinstance(self.content_object, User):
        try:
            user = self.content_object
            user.is_active = False if self.suspended else True 
            user.save()
        except:
            raise RuntimeError('Unable to find user')
    return super().save(*args, **kwargs)

没有工作!

在分别实现它们时,我将用户实例保存了两次,并且每次 user.is_active 恢复为 True 并保存(即用户实例上的 post_save 信号将其打印两次,最后始终为 True)。我检查了我的代码,我没有在其他任何地方触摸 user.is_active。我也可以从管理员或外壳更改 is_active 。怎么了?

标签: djangodjango-modelsdjango-views

解决方案


问题出在form_valid()方法上。该问题是由之前单独保存暂停的代码引起的super().form_valid(form)。代码通过将其更改为:

def form_valid(self, form):
    suspension, created = Suspension.objects.get_or_create(
            content_type = ContentType.objects.get(app_label="myapp", model="suspension"),
            object_id = self.kwargs['pk'],
        )
    suspension.reason = form.cleaned_data['reason']
    suspension.suspended = form.cleaned_data['suspended']
    form.instance = suspension # <-- here's the solution: we overwrite the form.instance and let django do its job.
    user = suspension.content_object
    user.is_active = False if suspension.suspended else True
    user.save()
    return super().form_valid(form)

推荐阅读