Maxim
Maxim

Reputation: 507

Showing validation error from m2m_changed signal in django admin

I am trying to validate that the variable foo is the same for MyModel and Item before adding it as a m2m. I want to raise a ValidationError in the admin if it is not.

models.py

class Item(models.Model):
    foo = models.CharField(max_length=200)    

class MyModel(models.Model):
    foo = models.CharField(max_length=200)
    items = models.ManyToManyField(Item)

signals.py

@receiver(m2m_changed, sender=MyModel.items.through)
def my_validator(sender, instance, action, pk_set, **kwargs):
    if action == 'pre_add':
        if Item.objects.filter(id__in=pk_set, foo=instance.foo).count() != len(pk_set):
            raise ValidationError({'items': ["Foo doesn't match"]})

Is there a way for the ValidationError to show up properly in the admin and not as a 500 error.

I wasn't able to come up with a solution to use MyModel's clean method to validate the same value of foo. Any advice is appreciated.

Upvotes: 4

Views: 1822

Answers (1)

Nagaraj Tantri
Nagaraj Tantri

Reputation: 5242

Create a form class with clean method and modify your admin class to use the form. Read this:

Like:

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    search_fields = ('foo', 'items__foo')
    list_display = ('foo', 'items__foo')
    form = MyModelForm


class MyModelForm(forms.ModelForm):

    def clean(self):
        """
        This is the function that can be used to 
        validate your model data from admin
        """
        super(MyModelForm, self).clean()
        foo = self.cleaned_data.get('foo')
        pk_set = Item.objects.all().values_list("id")

        # The logic you were trying to filter..
        if Item.objects.filter(id__in=pk_set).count() != len(pk_set):
            raise ValidationError({'items': ["Foo doesn't match"]})

Upvotes: 5

Related Questions