SaeX
SaeX

Reputation: 18681

Django recursive relationship

I'm using Django 1.5 and am struggling with something that I guess is pretty basic.

I've got following Persons model:

class Person(models.Model):
    contact_person = models.ManyToManyField(ContactPerson)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
...

The goal is to add a partner of the person to the model. I don't want the partner or the person to be superior to the other; they should be equal. In other words, when looking up a person, his/her partner should appear as well (if there is one). I need to be able to add the partner once, either at the woman's or at the men's side (I don't want to link them two times).

I've searched the documentation for OneToOneFields, but recursive OneToOnes don't seem to be supported, i.e. I get a NameError ("name 'Person' is not defined") when I try:

partner = models.OneToOneField(Person, blank=true, null=true)

Can anyone point me in the right direction?

Upvotes: 2

Views: 5602

Answers (2)

Sudipta
Sudipta

Reputation: 4971

Try this:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    ...
    partner = models.OneToOneField('self', null=True, blank=True)

    def save(self, checkPartner = True, *args, **kwargs):
        super(Person, self).save()
        if self.partner and checkPartner:
            self.partner.partner = self
            self.partner.save(checkPartner = False)
  • Null true on partner field, has to be enabled because the first person to be saved will not have any partner.
  • checkPartner parameter has been added so that save() doesn't fall into an infinite loop

Upvotes: 4

Samuele Mattiuzzo
Samuele Mattiuzzo

Reputation: 11038

https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey

partner = models.OneToOneField('Person', blank=true, null=true)

or in alternative, if you're on the same class

partner = models.OneToOneField('self', blank=true, null=true)

quotes are everything, in this case

def save(self, *args, **kwargs):
    # call to super, we want self.partner to be set
    super(Person, self).save(*args, **kwargs)

    # this is necessary to avoid infinite save loops on partner's save call
    # at this point, you have a partner
    # this won't work if your partner has already a partner
    # but it's easy to go from here
    if not self.partner.partner:
        self.partner.partner = self
        self.partner.save()

Upvotes: 4

Related Questions