我正在尝试确定在两个模型之间建立“零对一”关系的最佳方法。例如,名为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)?
非常感谢任何建议。
答案 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
参数。