1

我需要防止用户从模型中的管理员列表中自我杀死:

class Organization(models.Model):       
    administrators = models.ManyToManyField(User, blank=True, null=True, help_text=_('Administrators are people that manage the organization'))

    def save(self, *args, **kwargs):
        # --- some specific code here ---
        super(Organization, self).save(*args, **kwargs)
        if self.user_id not in self.administrators.values_list('id', flat=True):
            self.administrators.add(self.user)
            # super(Organization, self).save(*args, **kwargs)
            self.save()                
            # assert False, self.administrators.all() # <- it works, if assert goes here

好吧,这里可能是施了什么黑魔法,让我们试试一个post_save信号:

def organization_post_save(sender, instance, created, **kwargs):
    if instance.user_id not in instance.administrators.all().values_list('id', flat=True):
        instance.administrators.add(instance.user)
        instance.save()
        # assert False, '?'

只有当断言发生时,它才会在管理员列表中添加一个用户。好吧,可能是黑魔法又出现了,我们试试:

def organization_m2m_changed(sender, instance, action, reverse, model, pk_set, using, **kwargs):
    if instance.user_id not in instance.administrators.all().values_list('id', flat=True):
        instance.administrators.add(instance.user_id)

m2m_changed.connect(organization_m2m_changed, sender=Organization.administrators.through)

当然,maximum recursion depth exceeded。怎么了?这种痛苦是不可阻挡的:(

UPD1

看来,该post_save方法称为BEFORE m2m 关系已保存,因此它遇到了竞争条件,并且新数据被替换为空的表单数据。这是一个糟糕的解决方案:

def organization_m2m_changed(sender, instance, action, reverse, model, pk_set, using, **kwargs):

    if not instance.administrators.filter(id=instance.user_id).exists():
        if action.startswith('post_'):
            instance.administrators.add(instance.user)

现在我想知道在完成模型的所有工作后 Django 会发出什么信号?

PS没有魔法。:(

UPD2 谎言

表格.py

class OrganizationEditForm(forms.ModelForm):    
    class Meta:
        model = Organization
        exclude = ['user']
        widgets = floppyforms_widgets(Organization)

视图.py

@login_required
def edit_organization(request, organization_id=None):
    user = request.user
    c = Context({'user': user})

    instance = get_object_or_404(Organization, id=organization_id) if organization_id else Organization(user=user)
    form = OrganizationEditForm(request.POST or None, request.FILES or None, instance=instance)

    if form.is_valid():
        form.save()
        messages.success(request, _('Organization saved successfully'))
        return HttpResponseRedirect(reverse('organizations'))

    c['form'] = form
    c['instance'] = instance

    return render_to_response('cat/edit_organization.html', c, context_instance=RequestContext(request))
4

1 回答 1

0

你得到递归错误,因为你在 Organization.save() 内部调用 self.save()。不要这样做,如果你想在覆盖 save() 的同时保存,调用超类的 save() 版本而不是你自己的 save()。

在将实例添加到 m2m 关系之前,关系的双方必须已经有一个主键(即已经插入到数据库中)。这意味着您不能将未保存、未创建的对象添加到 m2m 关系。

做这个:

organisation.save()
user.save()
organisation.administrators.add(user)

我建议在 View 或 Form 中执行此操作,因为如果模型的 save 方法也保存了用户的模型,这是非常出乎意料的(尽管它也应该在模型的 save() 中工作)

于 2014-01-11T20:23:28.687 回答