开发者

Django: "ZeroToOneField" DoesNotExist Error

I'm trying to determine the best way to make a "zero-to-one" relationship between two models. For example, a model named Post can have zero or one related model instances of a Model called PostExtra. I'd like the reverse to be true as well.

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)
开发者_如何学JAVA

Here, I can create a Post()

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

As above, since I made Post.extra a OneToOneField with blank=True/null=True, p.extra will return Null if no PostExtra is assigned. However, if I do the reverse and try to access PostExtra.post, I get a DoesNotExist error.

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

I tried assigning a property on PostExtra to override the PostExtra.post using a property, but I still get the error. Has anyone found a way to get OneToOneFields to not throw an exception (and return Null) when trying to access a non-existent related element?

Any advice is much appreciated.


You would need to specify a different related_name on your relationship in order to make this type of code work.

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')

You can then access the post in a few different ways:

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

Ninja Edit:
The question may be raised, "Why do I have to do it this way?". The answer is because when the Django model classes set up your PostExtra object, it is creating PostExtra.post as a reference back to Post. I'm not familiar with the code itself, but I doubt it checks to make sure the coast is clear before doing the assignment, since the programmer told it to make that relation. As a result, you have to specify a non-conflicting property for Django's model classes to use, thus the related_name argument.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜