Django OneToOneField RelatedObjectDoesNotExist

2023-01-31
#python #django #english

A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.

This is most useful as the primary key of a model which “extends” another model in some way;but sometimes it may cause RelatedObjectDoesNotExist if the certain one doesn't exist.

Example

take a example from stackoverflow Django : OneToOneField - RelatedObjectDoesNotExist

class Answer(models.Model):
    answer = models.CharField(max_length=300)
    question = models.ForeignKey('Question', on_delete=models.CASCADE)

    def __str__(self):
        return "{0}, view: {1}".format(self.answer, self.answer_number)


class Vote(models.Model):
    answer = models.OneToOneField(Answer, related_name="votes", on_delete=models.CASCADE)
    users = models.ManyToManyField(User)

    def __str__(self):
        return str(self.answer.answer)[:30]

it will be ok,if we only use Answer:

>>> Answer.objects.all()[0]
<Answer: choix 1 , view: 0>

when it comes to Vote:

>>> Answer.objects.all()[0].votes
???

⚠️ Once if the answer has no votes, it will raise RelatedObjectDoesNotExist error

    raise self.RelatedObjectDoesNotExist(
questions.models.Answer.votes.RelatedObjectDoesNotExist: Answer has no votes.

Solution

How to avoid this ? Of course,you can catch the error simply

answer = Answer.objects.all().first()
try:
   vote = answer.votes
except Answer._meta.model.related_field.RelatedObjectDoesNotExist as e:
   vote = None

Also, use hasattr instead

answer = Answer.objects.all().first()
vote = answer.votes if hasattr(answer, 'votes') else None

Refences

Django : OneToOneField - RelatedObjectDoesNotExist