【问题标题】:Django : OneToOneField - RelatedObjectDoesNotExistDjango:OneToOneField - RelatedObjectDoesNotExist
【发布时间】:2020-03-26 17:03:48
【问题描述】:

我的模型中有以下两个类:

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]

在shell中我取第一个答案:

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

我想获得 Vote 对象:

>>> 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 无法识别。你能帮帮我吗?

【问题讨论】:

  • 您在这里使用了OneToOneField?这意味着每个Vote 指向一个不同的 答案?那么每个Answer最多有一个Vote,因此some_answer.votes将立即查询Vote对象,如果它不存在,则会引发DoesNotExists错误。

标签: python django one-to-one


【解决方案1】:

您的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,如果相关的 Vote 存在,answer.votes 将始终返回单个实例。因此,使用related_name='vote'(不带 s)会更合适

【讨论】:

    【解决方案2】:

    你在这里使用了OneToOneField。因此,这意味着每个Vote 都指向一个不同 Anwer 对象。因此每个Answer最多有一个Vote。像some_answer.votes 这样的查询将立即查询该Vote 对象,如果它不存在,它将引发RelatedObjectDoesNotExist 错误(这是ObjectDoesNotExist 异常的子类)。所以related_name本身被识别了,但是没有相关的Vote对象。

    然而,在这里使用OneToOneField 是令人惊讶的。这意味着每个投票都指向一个唯一的Answer?我想你可能想在这里使用ForeignKey,否则related_name='votes' 没有多大意义。

    【讨论】:

      【解决方案3】:

      通过查询Vote 模型而不使用OneToOne 关系来检查您的Answer 是否有Vote

      尝试做:

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

      额外提示,您应该在related_name 上使用单数词(vote 而不是votes),因为它是 OneToOne,这意味着答案只能投票一次(反之亦然)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-27
        • 2015-01-19
        • 1970-01-01
        • 2020-07-17
        • 2020-12-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多