fish_ball fish_ball - 3 months ago 19
Python Question

Check if a OneToOne relation exists in Django

Now I'm using django 1.6

I have two models relates with a

OneToOneField
.

class A(models.Model):
pass

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





First see my code that points out the problem:

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


Now the problem is, if I want to check a
A
object, to judge whether it exists a
B
objects referencing it. How can I do?

The valid way I tried is only to try and catch an exception, but is there any other prettier way?




My effort:

1 - The below code works, but is too ugly!

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


2 - I also tried to check the attributes in a, but not working:

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





Do you meet the same problem, friends? Please point me a way, thank you!

Answer

So you have a least two ways of checking that. First is to create try/catch block to get attribute, second is to use 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)

Please try to avoid bare except: clauses. It can hide some problems.

The second way is:

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)

In both cases you can use it without any exceptions:

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

There is no other way, as throwing the exception is default behaviour from Django One to One relationships.

And this is the example of handling it from official documentation.

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