Check if a OneToOne relation exists in Django

20,362

Solution 1

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.

Solution 2

Individual model classes provide a more specific exception called DoesNotExist that extends ObjectDoesNotExist. My preference is to write it this way:

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

Solution 3

hasattr works fine with Django1.11 ! You may use getattr for shorter version:

getattr(self, 'field', default)

In your case

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

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

Share:
20,362

Related videos on Youtube

Alfred Huang
Author by

Alfred Huang

一切有为法, 如梦幻泡影。 如露亦如电, 应作如是观。

Updated on July 04, 2020

Comments

  • Alfred Huang
    Alfred Huang almost 4 years

    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!

    • Yogesh dwivedi Geitpl
      Yogesh dwivedi Geitpl over 9 years
      I think this will work for you, please keep in mind change your class name at least in 2 later. b = hasattr(a_class_object, 'b class') and a.ref_b or None. I am using same and working for me.
    • Alfred Huang
      Alfred Huang over 9 years
      @Yogesh I don't quite catch, could you please post a more detail solution?
    • beruic
      beruic almost 7 years
      hasattr seems to work fine for me on Django 1.8.17 with Python 2.
  • Duda Nogueira
    Duda Nogueira over 8 years
    Great answer! Thanks!
  • user2230901
    user2230901 over 6 years
    why not put b = None in the except clause? (to save a line)