user1399216
user1399216

Reputation: 35

How to make Django OneToOneField mutually exclusive across classes

I have: myARecord = models.OneToOneField(ClassA,...) that is used by two different classes, B and C.

In the Django admin, it lets me create a B record and a C record that both reference the same A record. Two instances of either B or C cannot reference the same A record as expected.

How do I enforce that mutual exclusivity for all records of both B and C classes?

Upvotes: 0

Views: 372

Answers (1)

Vedran
Vedran

Reputation: 1150

A OneToOneField is basically a foreign key with unique=True set, which means:

  1. because it is a foreign key, the instance that it is referencing can be referenced by other instances that have it as a foreign key value as well
  2. unique=True means that the value should be unique throughout the table, meaning that two instances of model ClassB cannot have the same foreign key value to the pointing to ClassA, but one instance of ClassB can have the same foreign key value to the ClassA model as one instance of ClassC and so forth

That being said, enforcing a strict one-to-one relationship this way can be done only between two tables, not three. In that case you could create some custom validation, for example:

class ClassB(models.Model):
    a_reference = models.OneToOneField(ClassA)

    def save(self, *args, **kwargs):
        class_c_instances_with_same_value = ClassC.objects.filter(a_reference=self.a_reference)
        if class_c_instances_with_same_value:
            raise ValidationError
        super(ClassB, self).save(*args, **kwargs)

but you would have to do that for all your classes. Maybe create a mixin class and use that one in all classes where you want to enforce this.

Note: As Kevin Christopher Henry pointed out in the comments, you might wanna keep your validations in the clean() method.

Upvotes: 1

Related Questions