使用TabularInline

时间:2017-12-12 09:04:49

标签: django django-forms django-admin

我有2个模型所有者和物品。

class Owner(admin.ModelAdmin):
    is_active = models.BooleanField(default=False)


class Item(admin.ModelAdmin):
    owner = models.ForeignKey(Owner, related_name='items', on_delete=models.CASCADE)
    is_active = models.BooleanField(default=False)

遵守以下规则:

1)如果所有者is_activeFalse,则Item无法生效 2)如果Owner is_active True变为False Item(s),则is_active False变为def clean(self): super().clean() if self.is_active: if not self.owner.is_active: raise ValidationError( {'is_active': 'The Owner need to be checked an validated first'}) return self.is_active

规则1,在项目模型中:

 def save(self, *args, **kwargs):
        # if the active state was changed and is False
        if self.__original_is_active != self.is_active and self.is_active is False:
            # update does direct changes in database doesn't call save or signals
            self.items.update(is_active=False)
        super().save(*args, **kwargs)

规则2,在模型中:(在stackoverflow的帮助下):

Item Model

问题:

我在Owner Admin中添加了TabularInline is_active

对于规则2,当我​​将Owner TrueFalse切换到is_active并尝试保存时,会出现Rule1(ValidationError),但不能保存。

这对我来说很奇怪,因为产品Owner Form的更新是在is_active保存之前完成的,所以它应该具有以前的值。

我认为Item的{​​{1}}已更新为False,但在保存尝试时再次True(因为在UI中保持这种方式),但是我不知道如何解决它。

2 个答案:

答案 0 :(得分:1)

在Django admin中,当您保存表单时。首先验证它,然后调用save方法。

您可以覆盖默认的django表单。例如:

class CompanyAdminForm(forms.ModelForm):
    def clean(self):
        self.instance.products.update(is_active=False)
        return self.cleaned_data

class CompanyAdmin(admin.ModelAdmin):
    form = CompanyAdminForm

或者您可以将产品清洁方法更改为

def clean(self):
    super().clean()
    if self.is_active and not self.company.is_active:
        self.is_active = False
    return self.is_active

答案 1 :(得分:1)

我已转载您的问题并进行了测试。经过一些调试后,我发现以下内容

问题

保存Owner模型时,管理表单会对其进行验证并对其执行full_clean。在模型实例上调用full_clean时,无论是否将其保存在db中,都会为其分配更新的值。这意味着“所有者”的is_active值现在为False(但尚未保存在db中)。

在将此实例保存到db之前,django admin会清除所有表单集实例并为它们分配新值(如果有更新)。这就是您要验证Item实例的地方。

已更新(但未保存在db中)所有者已分配给所有Item实例。而且这里的代码失败,因为Item实例已更新了所有者实例,而所有者实例已更新了is_active的值。

解决方案

我建议您使用相同的技巧进行条件检查,就像检查所有者的is_active的值是否已更改一样。只需将__original_is_active字段从私有更改为受保护,然后将其用于验证即可

def clean(self):
    super().clean()
    if self.is_active:
        if not self.owner._original_is_active:
            raise ValidationError(
                {'is_active': 'The Owner need to be checked an validated first'})
    return self.is_active

所有者实例将具有is_active的更新值,但还具有缓存在_original_is_active中的初始值。

我希望这能解决您的困惑和问题。