Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch IntegrityError in Django Admin

Working with Django 1.4

I would like to catch an Integrity Error when a user does enter a duplicate value. At this moment the application just shows the default Django error page. (debug = True)

model

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")

admin

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)

form

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

At this moment I get an error page showing a ValidationError instead of an IntegrityError. (Which makes perfect sense)

How would I be able to properly catch the IntegrityError and show it at the top of the Django admin page?

Update

I noticed there was a form in there to check if foo.parent.bar.identifier matches foo.bar.identifier.
When I remove the form from the ViewAdmin the error handling works as expected.

So I guess the question here would be: How do I check if the parents match when saving the admin form?

like image 308
Johan Vergeer Avatar asked Apr 15 '16 09:04

Johan Vergeer


1 Answers

You shouldn't try to handle this in the save_model method. The admin view expects the save_model method to succeed, so does not handle integrity or validation errors. If the save_model method is raising IntegrityError, then the problem is probably somewhere else.

I think your problem is that you have forgotten to call the parent class' clean method when you overrode it. This prevents the form from validating the unique field. See the warning in the docs for more info.

class FooForm(forms.ModelForm):

    def clean(self):
        cleaned_data = super(FooForm, self).clean()
        parent = cleaned_data.get("parent")
        ...
        return cleaned_data
like image 148
Alasdair Avatar answered Sep 19 '22 23:09

Alasdair