Wednesday, September 15, 2010

Using ObjectDoesNotExist to catch DoesNotExist errors

The Django documentation discusses the DoesNotExist error as follows:

http://docs.djangoproject.com/en/dev/ref/models/querysets/#id5
get() raises a DoesNotExist exception if an object wasn't found for the given parameters. This exception is also an attribute of the model class. Example:

Entry.objects.get(id='foo') # raises Entry.DoesNotExist

The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist, so you can target multiple DoesNotExist exceptions.
How does it actually work? The Stack Overflow thread has this discussion:
http://stackoverflow.com/questions/2143506/django-where-does-doesnotexist-come-from

If you dig through the django.db.models.base.py file, you see these lines:
class ModelBase(type):

     super_new = super(ModelBase, cls).__new__
     new_class = super_new(cls, name, bases, {'__module__': module})

     if not abstract:
            new_class.add_to_class('DoesNotExist',
                    subclass_exception('DoesNotExist', ObjectDoesNotExist, module))
            new_class.add_to_class('MultipleObjectsReturned',
                    subclass_exception('MultipleObjectsReturned', MultipleObjectsReturned, module))

.
.
.
   def add_to_class(cls, name, value):
        if hasattr(value, 'contribute_to_class'):
            value.contribute_to_class(cls, name)
        else:
            setattr(cls, name, value)


You then have to wade through the bottom of the file to see what subclass_exception() actually does:
if sys.version_info < (2, 5):
    # Prior to Python 2.5, Exception was an old-style class                                                                                                                                                                                  
    def subclass_exception(name, parent, unused):
        return types.ClassType(name, (parent,), {})
else:
    def subclass_exception(name, parent, module):
        return type(name, (parent,), {'__module__': module})
It seems that Django creates a DoesNotExist exception for the class itself dynamically. The parent object is ObjectDoesNotExist, so you can use that parent to be able to catch exceptions thrown by multiple classes.

No comments:

Post a Comment