Django: OneToOneField - RelatedObjectDoesNotExist - PullRequest
1 голос
/ 26 марта 2020

У меня есть два следующих класса в моей модели:

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]

В оболочке я беру первый ответ:

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

Я хочу получить объект голосования:

>>> Answer.objects.all()[0].votes
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Users\Hippolyte\AppData\Roaming\Python\Python38\site-packages\django\db\models\fields\related_descriptors.py", line 420, in __get__
    raise self.RelatedObjectDoesNotExist(
questions.models.Answer.votes.RelatedObjectDoesNotExist: Answer has no votes.

Но произошла ошибка.

Я не понимаю, почему related_name не распознается. Не могли бы вы помочь мне?

Ответы [ 3 ]

1 голос
/ 26 марта 2020

Проверьте, имеет ли Answer значение Vote, запросив модель Vote без использования отношения OneToOne

Попробуйте выполнить:

ans = Answer.objects.all()[0]
Vote.objects.filter(answer_id = ans.id).all()

Дополнительный совет, вы должны использовать единственное слово для related_name (vote вместо votes), потому что это OneToOne, что означает, что Ответ может получить только один голос (и наоборот)

1 голос
/ 26 марта 2020

Ваш related_name распознается, но назначается экземпляру, только если связанный объект существует.

В вашем случае в вашей базе данных нет экземпляра Vote, где его поле answer указывает на ваш Answer экземпляр

Просто перехватите исключение и верните None, если вы хочу продолжить:

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

Если вы хотите сократить это, вы можете использовать hasattr(answer, 'vote'), чтобы проверить, но это замаскирует ВСЕ исключения, возникающие из поиска БД, если таковые имеются

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

Обратите внимание, что поскольку вы использовали OneToOneField, answer.votes всегда будет возвращать один экземпляр, если существует связанный Vote. Таким образом, было бы более целесообразно использовать related_name='vote' (без s)

1 голос
/ 26 марта 2020

Вы использовали OneToOneField здесь. Таким образом, это означает, что каждый Vote указывает на другой Anwer объект. Таким образом, максимум один Vote на Answer. Запрос, подобный some_answer.votes, немедленно запросит этот объект Vote, и, если он не существует, он выдаст ошибку RelatedObjectDoesNotExist (которая является подклассом исключения ObjectDoesNotExist). Таким образом, сам related_name распознается, но нет никакого связанного Vote объекта.

Однако удивительно использовать OneToOneField здесь. Это означает, что каждый голос указывает на уникальный Answer? Я думаю, что вы, вероятно, хотите использовать ForeignKey здесь, так как в противном случае related_name='votes' не имеет особого смысла.

...