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

24 投票
6 回答
9601 浏览
提问于 2025-04-16 05:38

我有一个这样的Django类:

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

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

如果没有与Breakfast相关的Egg,那么breakfast.egg == None是可能的吗?

编辑:我忘了提:我不想把related_name改成类似related_name="_egg",然后再用这样的方式:

@property
def egg(self):
    try:
        return self.egg
    except ...:
        return None

因为我在查询中使用了egg这个名字,我不想把查询改成用_egg

6 个回答

5

我知道在外键(ForeignKey)中,你可以设置 null=True,这样就允许这个模型不指向其他任何模型。而一对一(OneToOne)其实只是外键的一种特殊情况。

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
9

我刚遇到这个问题,发现了一个奇怪的解决办法:如果你使用了select_related(),那么如果没有相关的数据行,那个属性会变成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

不过我不确定这算不算一个稳定的特性。

12

这个自定义的 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

使用方法如下:

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

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

breakfast = Breakfast()
assert breakfast.egg == None

撰写回答