Django:如果相关对象不存在,从OneToOneField返回'None'?

Dav*_*ver 21 python django django-models

我有一个像这样的Django类:

class Breakfast(m.Model):
    # egg = m.OneToOneField(Egg)
    ...

class Egg(m.Model):
    breakfast = m.OneToOneField(Breakfast, related_name="egg")
Run Code Online (Sandbox Code Playgroud)

是否有可能有breakfast.egg == None,如果没有Egg相关的Breakfast

编辑:忘记提及:我宁愿不改变related_name类似的东西related_name="_egg",然后有类似的东西:

@property
def egg(self):
    try:
        return self.egg
    except ...:
        return None
Run Code Online (Sandbox Code Playgroud)

因为我egg在查询中使用该名称,我宁愿不必将查询更改为使用_egg.

eju*_*ovy 9

我刚遇到这个问题,并找到了一个奇怪的解决方案:如果你selectRelated(),那么如果不存在相关行,该属性将为None,而不是引发错误.

>>> print Breakfast.objects.get(pk=1).egg
Traceback (most recent call last):
...
DoesNotExist: Egg matching query does not exist

>>> print Breakfast.objects.select_related("egg").get(pk=1).egg
None
Run Code Online (Sandbox Code Playgroud)

我不知道这是否可以被认为是一个稳定的功能.


Bry*_*nan 9

这个自定义django字段将完全按照您的要求执行:

class SingleRelatedObjectDescriptorReturnsNone(SingleRelatedObjectDescriptor):
    def __get__(self, *args, **kwargs):
        try:
            return super(SingleRelatedObjectDescriptorReturnsNone, self).__get__(*args, **kwargs)
        except ObjectDoesNotExist:
            return None

class OneToOneOrNoneField(models.OneToOneField):
    """A OneToOneField that returns None if the related object doesn't exist"""
    related_accessor_class = SingleRelatedObjectDescriptorReturnsNone
Run Code Online (Sandbox Code Playgroud)

要使用它:

class Breakfast(models.Model):
    pass
    # other fields

class Egg(m.Model):
    breakfast = OneToOneOrNoneField(Breakfast, related_name="egg")

breakfast = Breakfast()
assert breakfast.egg == None
Run Code Online (Sandbox Code Playgroud)

  • 惊人的!顺便说一句,1.10 中的界面几乎没有变化。SingleRelatedObjectDescriptor 现在是 ReverseOneToOneDescriptor 并且 ``__get__``` 参数是 (self, instance, cls=None) (2认同)

Ome*_*tel 6

我知道,null=True当你想让模型不指向任何其他模型时,你可以拥有ForeignKey .OneToOne只是ForeignKey的一个特例:

class Place(models.Model)
    address = models.CharField(max_length=80)
class Shop(models.Model)
    place = models.OneToOneField(Place, null=True)
    name = models.CharField(max_length=50)
    website = models.URLField()

>>>s1 = Shop.objects.create(name='Shop', website='shop.com')
>>>print s1.place
None
Run Code Online (Sandbox Code Playgroud)