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.
精彩评论