Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.8: How can I ensure that of Two Fields in a Model, At Least One or Only One must meet a condition?

For context, here is a menu system.

class Menu(models.Model):
    ...


class Link(models.Model):
    ...


class MenuItem(models.Model):
    menu = models.ForeignKey(Menu)
    submenu = models.ForeignKey(Menu, related_name='submenu', blank=True, null=True)
    link = models.ForeignKey(Link, blank=True, null=True)
    position = models.IntegerField()

I have two results I'm looking to achieve:

  • At least one of Submenu and Link must not be Null (submenu titles can have a link)
  • Only one of Submenu and Link must be null (submenu titles cannot have a link)

Any advanced validation is new to me, so a code example would be very helpful.

In this example, data will only be added via Django Admin

like image 757
StringsOnFire Avatar asked Aug 03 '15 10:08

StringsOnFire


1 Answers

The documentation around model validation is poor. There are numerous (closed) issues referring to it, but it's still unclear.

This solution works, without making changes to any Forms:

from django.core.exceptions import ValidationError

class MenuItem(models.Model):
    ...

    def clean(self):
        super(MenuItem, self).clean()
        if self.submenu is None and self.link is None:
            raise ValidationError('Validation error text')

clean() has some default validation functionality, so the clean belonging to Model needs be called first.

The above ensures that at least one of the two fields are used, and raises the exception if not. I have only tested this in the Admin interface.

I don't know if this is the correct way to do this, and would love to know more if someone has a better understanding of model validation in Django. Coming from another languages and frameworks, this does feel like the natural way to write custom validation.

like image 136
StringsOnFire Avatar answered Nov 03 '22 12:11

StringsOnFire