检查Django中是否存在OneToOne关系

pjngdqdw  于 2023-03-24  发布在  Go
关注(0)|答案(4)|浏览(223)

现在我用的是Django 1.6
我有两个模型与OneToOneField相关。

class A(models.Model):
    pass

class B(models.Model):
    ref_a = models.OneToOneField(related_name='ref_b', null=True)

首先看看我的代码,它指出了问题:

a1 = A.objects.create()
a2 = A.objects.create()
b1 = B.objects.create()
b2 = B.objects.create(ref_a=a2)

# then I call:
print(a1.ref_b)  # DoesNotExist Exception raised
print(a2.ref_b)  # returns b2
print(b1.ref_a)  # returns None
print(b2.ref_a)  # returns a2

现在的问题是,如果我想检查一个A对象,判断它是否存在一个B对象引用它,我该怎么做?
我尝试的有效方法只是尝试捕获异常,但还有其他更好的方法吗?
我的努力:
1 -下面的代码工作,但太丑了!

b = None
try:
    b = a.ref_b
except:
    pass

2 -我也尝试检查a中的属性,但不起作用:

b = a.ref_b if hasattr(a, 'ref_b') else None

朋友们,你们是否也遇到同样的问题?请指点迷津,谢谢!

2nc8po8w

2nc8po8w1#

所以你至少有两种方法来检查它。第一种是创建try/catch块来获取属性,第二种是使用hasattr

class A(models.Model):
   def get_B(self):
       try:
          return self.b
       except:
          return None

class B(models.Model):
   ref_a = models.OneToOneField(related_name='ref_b', null=True)

请尽量避免使用裸露的except:子句,因为它可能会隐藏一些problems
第二种方式是:

class A(models.Model):
    def get_B(self):
       if(hasattr(self, 'b')):
           return self.b
       return None

class B(models.Model):
    ref_a = models.OneToOneField(related_name='ref_b', null=True)

在这两种情况下,您都可以使用它,没有任何例外:

a1 = A.objects.create()
a2 = A.objects.create()
b1 = B.objects.create()
b2 = B.objects.create(ref_a=a2)

# then I call:
print(a1.get_b)  # No exception raised
print(a2.get_b)  # returns b2
print(b1.a)  # returns None
print(b2.a)  # returns a2

没有其他方法,因为抛出异常是Django One to One relationships的默认行为。
这是一个从官方文档中处理它的例子。

>>> from django.core.exceptions import ObjectDoesNotExist
>>> try:
>>>     p2.restaurant
>>> except ObjectDoesNotExist:
>>>     print("There is no restaurant here.")
There is no restaurant here.
ddrv8njm

ddrv8njm2#

单个模型类提供了一个更具体的异常DoesNotExist,它扩展了ObjectDoesNotExist。我的首选方法是这样写:

b = None
try:
    b = a.ref_b
except B.DoesNotExist:
    pass
8mmmxcuj

8mmmxcuj3#

hasattr在Django1.11中运行良好!您可以使用getattr来获得更短的版本:

getattr(self, 'field', default)

就你而言

b = getattr(a, 'ref_b', None)

https://docs.python.org/3.6/library/functions.html#getattr

zbdgwd5y

zbdgwd5y4#

更干净使用基于OneToOneField的自定义django Field,这种方法将允许您使用直接访问-只需a.ref_b,结果将是instance or None

from django.db.models.fields.related import ReverseOneToOneDescriptor
from django.core.exceptions import ObjectDoesNotExist
from django.db import models

class SingleRelatedObjectDescriptorReturnsNone(ReverseOneToOneDescriptor):
    def __get__(self, *args, **kwargs):
        try:
            return super().__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 A(models.Model):
    pass

class B(models.Model):
    ref_a = OneToOneOrNoneField(related_name='ref_b', null=True)

相关问题