50
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.
15
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
- [Django]-Django: How to filter Users that belong to a specific group
- [Django]-Modulus % in Django template
- [Django]-Combining Django F, Value and a dict to annotate a queryset
14
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)
- [Django]-How to create an object for a Django model with a many to many field?
- [Django]-What does on_delete do on Django models?
- [Django]-How to access Enum types in Django templates
3
Much cleaner to use custom django Field based on OneToOneField
, this approach which will allow you to use direct access โ just a.ref_b
and result would be 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
so the example will look like
class A(models.Model):
pass
class B(models.Model):
ref_a = OneToOneOrNoneField(related_name='ref_b', null=True)
- [Django]-How to execute a Python script from the Django shell?
- [Django]-Django: Staff Decorator
- [Django]-Get the index of an element in a queryset
1
Extending mr. Coffee answer you can use context lib suppress method
import contextlib
class A(models.Model):
def get_B(self):
with contextlib.suppress(Exception):
return self.b
class B(models.Model):
ref_a = models.OneToOneField(related_name='ref_b', null=True)
- [Django]-Django Cannot set values on a ManyToManyField which specifies an intermediary model. Use Manager instead
- [Django]-How do I invalidate @cached_property in django
- [Django]-Does SQLAlchemy have an equivalent of Django's get_or_create?