在Django Admin中捕获IntegrityError

时间:2016-04-15 09:13:40

标签: python django django-admin

使用Django 1.4

我想在用户输入重复值时捕获完整性错误。此时应用程序只显示默认的Django错误页面。 (debug = True)

模型

class Foo(models.Model):
    name = models.Charfield(max_length=100, unique=True)
    identifier = models.CharField(max_length=100, unique=True)
    parent = models.ForeignKey("self", related_name="children")
    bar = models.ForeignKey(Bar, related_name="foos")

管理

from django.core.exceptions import ValidationError
from django.db import IntegrityError

class FooAdmin(admin.ModelAdmin):
    form = FooForm

    search_fields = ['name']
    list_display = ['name']

    def save_model(self, request, obj, form, change):
        try:
            obj.save()
        except IntegrityError as e:
            raise ValidationError(e)

形式

class FooForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)

        if self.instance.pk:
            self.fields["parent"].queryset = Foo.objects.filter(bar=self.instance.bar)

    def clean(self):
        bar_identifier = self.cleaned_data.get("bar").identifier

        parent = self.cleaned_data.get("parent")
        if parent is not None:
            parent_bar_identifier = parent.bar.identifier
            if bar_identifier != parent_bar_identifier:
                raise forms.ValidationError("Bar identifier should match parent Bar identifier")

        return self.cleaded_data

此时我收到一个错误页面,显示ValidationError而不是IntegrityError。 (这很有道理)

我如何才能正确捕获IntegrityError并将其显示在Django管理页面的顶部?

更新

我注意到有一个表单可以检查foo.parent.bar.identifier是否与foo.bar.identifier匹配 当我从ViewAdmin中删除表单时,错误处理按预期工作。

所以我想这里的问题是:如何在保存管理表单时检查父母是否匹配?

2 个答案:

答案 0 :(得分:2)

您不应该尝试在save_model方法中处理此问题。管理视图期望save_model方法成功,因此不处理完整性或验证错误。如果save_model方法提升IntegrityError,那么问题可能就在其他地方。

我认为你的问题是你忘了打电话给父母班级'当你覆盖它时的clean方法。这可以防止表单验证唯一字段。有关详细信息,请参阅the warning in the docs

class FooForm(forms.ModelForm):

    def clean(self):
        cleaned_data = super(FooForm, self).clean()
        parent = cleaned_data.get("parent")
        ...
        return cleaned_data

答案 1 :(得分:0)

或者6月某个时候可能会写:on_delete = models.DO_NOTHING

const data = 
  {
"MBB": [
  {
    "Name": "BYO Sim"
  },
  {
    "Name": "Device Sim"
  },
  {
    "Name": "Apple Watch"
  },
  {
    "Name": "Samsung Watch"
  }
],
"WB": [
  {
    "Name": "4G with Device"
  },
  {
    "Name": "4G without Device"
  },
  {
    "Name": "5G"
  }
]
}
;

const result = data['MBB'].map(({Name}) => Name);
console.log(result);