Skip to main content
 首页 » 编程设计

python之在 Django Admin 中捕获 IntegrityError

2024年10月24日31shangdawei

使用 Django 1.4

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

模型

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 中删除表单时,错误处理按预期工作。

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

请您参考如下方法:

您不应尝试在 save_model 方法中处理此问题。管理 View 期望 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