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?
Advertisement
Answer
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