Only allow filling one field or the other in Django model and admin

Viewed 729

I've got a simple Django model for a Group that has a list of Contacts. Each group must have either a Primary contact ForeignKey or a All contacts BooleanField selected but not both and not none.

class Group(models.Model):
    contacts = models.ManyToManyField(Contact)
    contact_primary = models.ForeignKey(Contact, related_name="contact_primary", null=True)
    all_contacts = models.BooleanField(null=True)

How can I ensure that:

  1. The model can't be saved unless either contact_primary or all_contacts (but not both) is set. I guess that would be by implementing the Group.save() method? Or should it be the Group.clean() method??

  2. In Django Admin either disable the other field when one is selected or at least provide a meaningful error message if both or none are set and the admin tries to save it?

Thanks!

1 Answers

The easiest way would be to override the save() method of your model:

class Group(models.Model):
    contacts = models.ManyToManyField(Contact)
    contact_primary = models.ForeignKey(Contact, related_name="contact_primary", blank=True, null=True)
    all_contacts = models.BooleanField(blank=True, null=True)

    def save(self, *args, **kwargs):
        if self.contact_primary is not None and self.all_contacts is not None:
            raise Exception("some error message here")  
        if self.contact_primary is None and self.all_contacts is None:
            raise Exception("some other error message here")  

        return super().save()

Notice that I added blank=True to your model fields. This is necessary if you want to insert null columns through the admin or through a form.

Update

If you want to raise a ValidationError, you must raise it from the model's clean() method. Otherwise, you will give a 500 error to the client, rather than an error message.

Related