2

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:

  • The previous Person that PersonA was married to should set its married-field to None
  • The new Person that PersonA is married to should update and set its married-field to PersonA (which in turn can trigger that the new Person's potentially previously married Person should set its married-field to None)

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

Daniel Wedlund
  • 804
  • 7
  • 18

3 Answers3

1

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.

dani herrera
  • 48,760
  • 8
  • 117
  • 177
0

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)
dylrei
  • 1,728
  • 10
  • 13
0

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).

Jon
  • 13
  • 3