How to make django association reference to itself

Viewed 24

I have:

class Direction(models.Model):
    left = models.OneToOneField(
        'self', on_delete=models.SET_NULL, null=True, related_name='right')
    right = models.OneToOneField(
        'self', on_delete=models.SET_NULL, null=True, related_name='left')

The error:

ant.Direction.left: (fields.E302) Reverse accessor for 'ant.Direction.left' clashes with field name 'ant.Direction.right'. HINT: Rename field 'ant.Direction.right', or add/change a related_name argument to the definition for field 'ant.Direction.left'.

How does one make this relationship so that a.left = b and b.right = a?

1 Answers

You can not use as related_name the same as the fields that have been defined. You likely do not want to work with two OneToOneFields anyway, you can define a single OneToOneField, and set the related name to the opposite, so:

class Direction(models.Model):
    left = models.OneToOneField(
        'self',
        on_delete=models.SET_NULL,
        null=True,
        related_name='right'
    )
    # no right

So now if a direction a has as .left a direction b, then b has as .right the object a.

If there is no .right, then accessing .right will raise a Direction.DoesNotExist exception, we can however fix this issue by making use of another for the related_name, and work with a property that will wrap it in a try-except:

class Direction(models.Model):
    left = models.OneToOneField(
        'self',
        on_delete=models.SET_NULL,
        null=True,
        related_name='_right'
    )
    
    @property
    def right(self):
        try:
            return self._right
        except Direction.DoesNotExist:
            return None

    @right.setter
    def _set_right(self, value):
        self._right = value
Related