Daniel Wedlund
Daniel Wedlund

Reputation: 814

Django symmetrical relation

I was trying to solve a simple problem with a site where a Person model has a married_to field as Foreign Key.

To maintain this when a user (PersonA) changes who he/she is married to the following should happen:

So what I tried was to override the save method something along the lines

    if self.pk is not None and self.married is not None:
        orig = Person.objects.get(pk=self.pk)
        orig.married.married = None
        orig.married.save()

    if self.married is not None:
        self.married.married = self
        self.married.save()

    super(Person, self).save()

I ran into maximum recursive problem etc. and started to search for answers but didnt find anythin conclusive.

What is the idiomatic way to do this for noobs like me...

Thanks

Upvotes: 2

Views: 214

Answers (3)

dani herrera
dani herrera

Reputation: 51705

option 1 Write your code avoid save method call:

if self.pk is not None and self.married is not None:
    Person.objects.filter(pk=orig.married.married.pk).update( married = None )

if self.married is not None:
    Person.objects.filter(pk=orig.married.pk).update( married = self )

super(Person, self).save()

option 2 Also, you can stop recursion with a conditional particular case:

if self.married is not None and self.married != self:
    self.married.married = self
    self.married.save()

right way Perhaps, the right relation in your scenario is OneToOneField ( you are talking about ForeignKey in your question) if a Person can be only be married with another one.

Upvotes: 1

Jon
Jon

Reputation: 13

Something like this will work.

class Person(models.Model):
    ...
    partner = models.OneToOneField('self', blank=true, null=true)

    def save(self, *args, **kwargs):
       # to avoid infinite looping on save.
       if not self.partner.partner:
            self.partner.partner = self
            self.partner.save()

This will on save simply equal partner fields (create a symmetrical relation).

Upvotes: 0

dylrei
dylrei

Reputation: 1736

I would implement this as a separate method, not as a part of save(). Assuming that "married" is an FK to the related Person:

class Person(models.Model):
    [...]
    def set_married(self, married_to):
        if self.married_id != married_to.id:   # <-- prevent recursion/looping
            self.married = married_to
            self.save()
            self.married.set_married(self)

Upvotes: 0

Related Questions