Django:“ZeroToOneField”DoesNotExist错误

时间:2011-07-27 16:42:50

标签: django model one-to-one

我正在尝试确定在两个模型之间建立“零对一”关系的最佳方法。例如,名为Post的模型可以具有名为PostExtra的Model的零个或一个相关模型实例。我也希望反过来也是如此。

from django.db import models

class PostExtra(models.Model):

    author = models.CharField(max_length=64)
    active = models.BooleanField(default=False)  

    """
    Assigned a property to prevent DoesNotExist error when calling 
    self.post, but property does not override self.post properly 
    for some reason. 
    """ 
    def _get_post(self):
        return_value=None
        try:
            return_value = self.post
        except:
            pass
        return return_value

    def _set_post(self, post):
        self.post = post

    post = property(_get_post, _set_post)

    def __unicode__(self):
        return "%s" % (self.author)

class Post(models.Model):

    title = models.CharField(max_length=64)
    text = models.TextField()
    extra = models.OneToOneField('a.PostExtra', blank=True, null=True)

    def __unicode__(self):
        return "%s" % (self.title)

在这里,我可以创建一个Post()

>>> p = Post(title="test 1", text="test text")
>>> p.save()
>>> p.extra    # this returns None as it should

如上所述,由于我将Post.extra设为一个具有空白= True / null = True的OneToOneField,如果没有分配PostExtra,则p.extra将返回Null。但是,如果我反过来并尝试访问PostExtra.post,我会收到DoesNotExist错误。

>>> pe = PostExtra(author='John Doe')
>>> pe.save()
>>> pe.post 
...
DoesNotExist: Post matching query does not exist.

我尝试在PostExtra上分配一个属性来使用属性覆盖PostExtra.post,但我仍然得到错误。有没有人找到一种方法让OneToOneFields在尝试访问不存在的相关元素时不抛出异常(并返回Null)?

非常感谢任何建议。

1 个答案:

答案 0 :(得分:3)

您需要指定其他related_name on your relationship才能使此类代码正常工作。

from django.core.exceptions import ObjectDoesNotExist
class PostExtra(models.Model):
    pass ## Brevity.
    def _get_post(self):
        return_value=None
        try:
            return_value = self._post
        except ObjectDoesNotExist: ## Be explicit if you can.
            pass
        return return_value
    def _set_post(self, post):
        self._post = post
    post = property(_get_post, _set_post)

class Post(models.Model):
    pass ## Brevity.
    extra = models.OneToOneField('a.PostExtra', blank=True,
                      null=True, related_name='_post')

然后,您可以通过几种不同的方式访问帖子:

>>> pe = PostExtra(author='John Doe')
>>> pe.save()
>>> pe.post
None
>>> pe._post
DoesNotExist: Post matching query does not exist.

忍者编辑:
可能会提出这样一个问题:“为什么我必须这样做呢?”。答案是因为当Django模型类设置了您的PostExtra对象时,它会创建PostExtra.post作为对Post的引用。我对代码本身并不熟悉,但我怀疑它在进行分配之前检查以确保滑行清晰,因为程序员告诉它要建立这种关系。因此,您必须为Django的模型类指定一个非冲突属性,即related_name参数。