4

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.

Maxim
  • 507
  • 1
  • 7
  • 18

1 Answers1

5

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"]})
Nagaraj Tantri
  • 5,172
  • 12
  • 54
  • 78
  • Thank you! Creating a ModelForm and validating it through there did the trick. I did set pk_set to self.cleaned_data.get("items") however. Not sure why you are using Item.objects.all(). Thanks again!! – Maxim Jul 03 '16 at 06:51
  • @Maxim I was not aware what exactly was pk_set you wanted to save and use, so thought, it would be `pk` values of Item tables and so `Item.object.all()` . Anyways, you are welcome.:) – Nagaraj Tantri Jul 03 '16 at 06:54
  • no worries, the actual validation logic is not really relevant. I appreciate your help a lot. Saved me a good chunk of time! Cheers – Maxim Jul 03 '16 at 07:12