关于python:检查Django中是否存在OneToOne关系

Check if a OneToOne relation exists in Django

现在我正在使用django 1.6

我有两个模型与OneToOneField有关。

1
2
3
4
5
class A(models.Model):
    pass

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

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

1
2
3
4
5
6
7
8
9
10
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 - 以下代码有效,但太难看了!

1
2
3
4
5
b = None
try:
    b = a.ref_b
except:
    pass

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

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

朋友们,你遇到同样的问题吗? 请指点我,谢谢!


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

1
2
3
4
5
6
7
8
9
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:条款。 它可以隐藏一些问题。

第二种方式是:

1
2
3
4
5
6
7
8
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)

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

1
2
3
4
5
6
7
8
9
10
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关系的默认行为。

这是从官方文档处理它的例子。

1
2
3
4
5
6
>>> from django.core.exceptions import ObjectDoesNotExist
>>> try:
>>>     p2.restaurant
>>> except ObjectDoesNotExist:
>>>     print("There is no restaurant here.")
There is no restaurant here.


单个模型类提供了一个名为DoesNotExist的更具体的异常,它扩展了ObjectDoesNotExist。 我的偏好是这样写:

1
2
3
4
5
b = None
try:
    b = a.ref_b
except B.DoesNotExist:
    pass


hasattr可以正常使用Django1.11!
您可以使用getattr来缩短版本:

1
getattr(self, 'field', default)

在你的情况下

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

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