Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Return 'None' from OneToOneField if related object doesn't exist?

Tags:

I've got a Django class like this:

class Breakfast(m.Model):
    # egg = m.OneToOneField(Egg)
    ...

class Egg(m.Model):
    breakfast = m.OneToOneField(Breakfast, related_name="egg")

Is it possible to have breakfast.egg == None if there is no Egg related to the Breakfast?

Edit: Forgot to mention: I'd rather not change the related_name to something like related_name="_egg", then have something like:

@property
def egg(self):
    try:
        return self.egg
    except ...:
        return None

Because I use the name egg in queries, and I'd rather not have to change the queries to using _egg.

like image 952
David Wolever Avatar asked Oct 17 '10 20:10

David Wolever


2 Answers

This custom django field will do exactly what you want:

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

To use it:

class Breakfast(models.Model):
    pass
    # other fields

class Egg(m.Model):
    breakfast = OneToOneOrNoneField(Breakfast, related_name="egg")

breakfast = Breakfast()
assert breakfast.egg == None
like image 107
Bryce Drennan Avatar answered Sep 30 '22 23:09

Bryce Drennan


I just ran into this problem, and found an odd solution to it: if you select_related(), then the attribute will be None if no related row exists, instead of raising an error.

>>> print Breakfast.objects.get(pk=1).egg
Traceback (most recent call last):
...
DoesNotExist: Egg matching query does not exist

>>> print Breakfast.objects.select_related("egg").get(pk=1).egg
None

I have no idea if this can be considered a stable feature though.

like image 30
ejucovy Avatar answered Sep 30 '22 23:09

ejucovy