Django Exceptions¶
Django raises some of its own exceptions as well as standard Python exceptions.
Django Core Exceptions¶
Django core exception classes are defined in django.core.exceptions
.
AppRegistryNotReady
¶
-
exception
AppRegistryNotReady
[source]¶ -
This exception is raised when attempting to use models before the app
loading process, which initializes the ORM, is
complete.
EmptyResultSet
¶
-
exception
EmptyResultSet
[source]¶ -
EmptyResultSet
may be raised during query generation if a query won’t
return any results. Most Django projects won’t encounter this exception,
but it might be useful for implementing custom lookups and expressions.
FieldDoesNotExist
¶
-
exception
FieldDoesNotExist
[source]¶ -
The
FieldDoesNotExist
exception is raised by a model’s
_meta.get_field()
method when the requested field does not exist on the
model or on the model’s parents.
SuspiciousOperation
¶
-
exception
SuspiciousOperation
[source]¶ -
The
SuspiciousOperation
exception is raised when a user has
performed an operation that should be considered suspicious from a security
perspective, such as tampering with a session cookie. Subclasses of
SuspiciousOperation
include:DisallowedHost
DisallowedModelAdminLookup
DisallowedModelAdminToField
DisallowedRedirect
InvalidSessionKey
RequestDataTooBig
SuspiciousFileOperation
SuspiciousMultipartForm
SuspiciousSession
TooManyFieldsSent
If a
SuspiciousOperation
exception reaches the ASGI/WSGI handler level
it is logged at theError
level and results in
aHttpResponseBadRequest
. See the logging
documentation for more information.
PermissionDenied
¶
-
exception
PermissionDenied
[source]¶ -
The
PermissionDenied
exception is raised when a user does not have
permission to perform the action requested.
ViewDoesNotExist
¶
-
exception
ViewDoesNotExist
[source]¶ -
The
ViewDoesNotExist
exception is raised by
django.urls
when a requested view does not exist.
MiddlewareNotUsed
¶
-
exception
MiddlewareNotUsed
[source]¶ -
The
MiddlewareNotUsed
exception is raised when a middleware is not
used in the server configuration.
ImproperlyConfigured
¶
-
exception
ImproperlyConfigured
[source]¶ -
The
ImproperlyConfigured
exception is raised when Django is
somehow improperly configured – for example, if a value insettings.py
is incorrect or unparseable.
FieldError
¶
-
exception
FieldError
[source]¶ -
The
FieldError
exception is raised when there is a problem with a
model field. This can happen for several reasons:- A field in a model clashes with a field of the same name from an
abstract base class - An infinite loop is caused by ordering
- A keyword cannot be parsed from the filter parameters
- A field cannot be determined from a keyword in the query
parameters - A join is not permitted on the specified field
- A field name is invalid
- A query contains invalid order_by arguments
- A field in a model clashes with a field of the same name from an
ValidationError
¶
-
exception
ValidationError
[source]¶ -
The
ValidationError
exception is raised when data fails form or
model field validation. For more information about validation, see
Form and Field Validation,
Model Field Validation and the
Validator Reference.
NON_FIELD_ERRORS
¶
-
NON_FIELD_ERRORS
¶
ValidationError
s that don’t belong to a particular field in a form
or model are classified as NON_FIELD_ERRORS
. This constant is used
as a key in dictionaries that otherwise map fields to their respective
list of errors.
BadRequest
¶
-
exception
BadRequest
[source]¶ -
The
BadRequest
exception is raised when the request cannot be
processed due to a client error. If aBadRequest
exception reaches the
ASGI/WSGI handler level it results in a
HttpResponseBadRequest
.
RequestAborted
¶
-
exception
RequestAborted
[source]¶ -
The
RequestAborted
exception is raised when an HTTP body being read
in by the handler is cut off midstream and the client connection closes,
or when the client does not send data and hits a timeout where the server
closes the connection.It is internal to the HTTP handler modules and you are unlikely to see
it elsewhere. If you are modifying HTTP handling code, you should raise
this when you encounter an aborted request to make sure the socket is
closed cleanly.
SynchronousOnlyOperation
¶
-
exception
SynchronousOnlyOperation
[source]¶ -
The
SynchronousOnlyOperation
exception is raised when code that
is only allowed in synchronous Python code is called from an asynchronous
context (a thread with a running asynchronous event loop). These parts of
Django are generally heavily reliant on thread-safety to function and don’t
work correctly under coroutines sharing the same thread.If you are trying to call code that is synchronous-only from an
asynchronous thread, then create a synchronous thread and call it in that.
You can accomplish this is withasgiref.sync.sync_to_async()
.
URL Resolver exceptions¶
URL Resolver exceptions are defined in django.urls
.
Resolver404
¶
-
exception
Resolver404
¶ -
The
Resolver404
exception is raised by
resolve()
if the path passed toresolve()
doesn’t
map to a view. It’s a subclass ofdjango.http.Http404
.
NoReverseMatch
¶
-
exception
NoReverseMatch
¶ -
The
NoReverseMatch
exception is raised bydjango.urls
when a
matching URL in your URLconf cannot be identified based on the parameters
supplied.
Database Exceptions¶
Database exceptions may be imported from django.db
.
Django wraps the standard database exceptions so that your Django code has a
guaranteed common implementation of these classes.
-
exception
Error
[source]¶
-
exception
InterfaceError
[source]¶
-
exception
DatabaseError
[source]¶
-
exception
DataError
[source]¶
-
exception
OperationalError
[source]¶
-
exception
IntegrityError
[source]¶
-
exception
InternalError
[source]¶
-
exception
ProgrammingError
[source]¶
-
exception
NotSupportedError
[source]¶
The Django wrappers for database exceptions behave exactly the same as
the underlying database exceptions. See PEP 249, the Python Database API
Specification v2.0, for further information.
As per PEP 3134, a __cause__
attribute is set with the original
(underlying) database exception, allowing access to any additional
information provided.
-
exception
models.
ProtectedError
¶
Raised to prevent deletion of referenced objects when using
django.db.models.PROTECT
. models.ProtectedError
is a subclass
of IntegrityError
.
-
exception
models.
RestrictedError
¶
Raised to prevent deletion of referenced objects when using
django.db.models.RESTRICT
. models.RestrictedError
is a subclass
of IntegrityError
.
HTTP Exceptions¶
HTTP exceptions may be imported from django.http
.
UnreadablePostError
¶
-
exception
UnreadablePostError
¶ -
UnreadablePostError
is raised when a user cancels an upload.
Sessions Exceptions¶
Sessions exceptions are defined in django.contrib.sessions.exceptions
.
SessionInterrupted
¶
-
exception
SessionInterrupted
[source]¶ -
SessionInterrupted
is raised when a session is destroyed in a
concurrent request. It’s a subclass of
BadRequest
.
Transaction Exceptions¶
Transaction exceptions are defined in django.db.transaction
.
TransactionManagementError
¶
-
exception
TransactionManagementError
[source]¶ -
TransactionManagementError
is raised for any and all problems
related to database transactions.
Testing Framework Exceptions¶
Exceptions provided by the django.test
package.
RedirectCycleError
¶
-
exception
client.
RedirectCycleError
¶ -
RedirectCycleError
is raised when the test client detects a
loop or an overly long chain of redirects.
Python Exceptions¶
Django raises built-in Python exceptions when appropriate as well. See the
Python documentation for further information on the Built-in Exceptions.
In this article, we will learn Django exception handling in a very brief and concise manner while covering most of the exceptions and error messages in Django.
Why do we need to handle exceptions?
As a developer, you will encounter various errors either while making the web APIs, templates, or while writing any other piece of code.
Dealing with them is a very time taking process but also is an essential task, and hence this critical skill of exceptions and error handling comes into the picture.
What are Exceptions?
Exceptions in coding are those types of events that lead to undesirable events. These are detected by run-time executives(like consoles and terminals) or by Operating Systems.
They need not necessarily stop the whole program but will lead to undesirable outputs.
For e.g :
Let’s say the client wants to see a particular object from the database. But for some reason, that specific object is not present there.
In this case, the server won’t come to a halt, but the client will get an error since the object is not present in the DB, which is undesirable.
The key difference between Exceptions and Errors
Errors are those events due to which the whole system will come to a halt, and the program will not execute.
Nothing can be done with errors; we can only detect and then make appropriate changes such that they don’t happen.
On the other hand, exceptions are something that the developers can deal with without letting the system come to a halt.
Types of Django Exceptions
There are many kinds of exceptions in Django, out of which five are extremely important and are used most frequently.
- Django Exception classes
- Django URL Resolver Exceptions
- Django Database Exceptions
- Django Http Exceptions
- Django Transaction Exceptions
We will learn about them in detail.
1) Django Exception classes
ID | Exception | Description |
---|---|---|
1 | AppRegistryNotReady | – It occurs when the Django models are loaded before the Django app itself. – This exception occurs when you are writing your own scripts and not with default Django app files. |
2 | ObjectDoesNotExist | As the name suggests, occurs when Object does not exist. |
3 | EmptyResultSet | Occurs when a query returns an empty set |
4 | FieldDoesNotExist | This occurs when Field doest not exist in a model. |
5 | MultipleObjectsReturned | This occurs when a query returns more than one result |
6 | SuspiciousOperation | This happens when the client does something suspicious for security reasons |
7 | PermissionDenied | Occurs when the user tries to perform a task which he is not allowed to |
8 | ViewDoesNotExist | Occurs when Views doesnt not exist |
9 | MiddlewareNotUsed | This occurs when particular middleware is not used in the MIDDLEWARE section of settings.py |
10 | ImproperlyConfigured | This occurs when somehow, Django is improperly configured. Usually doesn’t happen when working with default Django Files. |
11 | FieldError | Happens when there is an error in Model field |
12 | ValidationError | Happens when Data validation fails in forms or model forms. |
2) Django URL Resolver Exceptions
ID | Exception | Description |
---|---|---|
1 | Resolver404 | – Raised by the function resolve(), a part of Django.http.Http404 library. – The exception occurs when path() does not have a valid View to map. |
2 | NoReverseMatch | This occurs when the user searches a wrong endpoint. |
3) Django Database Exceptions
ID | Exception | Description |
---|---|---|
1 | DatabaseError | Occurs when DB is not available |
2 | IntegrityError | – This occurs when DB expects a value for a field but doesn’t get it from the user. – If True, Django will store empty values as NULL in the database. Default is False. |
3 | DataError | Occurs due to data-related issues |
4) Django Http Exceptions
This we have seen many times. These are the HTTP exceptions that we import from django.http library
ID | Exception | Description |
---|---|---|
1 | UnreadablePostError | Occurs when a user cancels an upload. |
5) Django Transaction Exceptions
ID | Exception | Description |
---|---|---|
1 | TransactionManagementError | This is raised for all the problems that occur due to database transactions |
Simple Implementation of Exception Handling in the Django app
We will do a simple DoesNotExist exception handling on an application that shows information about a particular item in the server.
The code is a part of the Web Application itemsapp built in the REST API article.
Itemsapp is a simple REST API application that allows clients to
- View a list of items present in the server (GET endpoint: hostwebsite/items)
- Add a new item into the DB (POST endpoint: hostwebsite/items)
- View a particular item (GET endpoint: hostwebsite/item/<id>)
- Edit a particular item (PUT endpoint: hostwebsite/item/<id>)
- Delete a particular item (DELETE endpoint: hostwebsite/item/<id>)
To learn how to make the complete web application, do checkout Rest API article.
Now we will create a webpage that shows the information about a particular item from the DB
- Create a ItemModel in models.py to store information about items:
from django.db import models # Create your models here. class ItemsModel(models.Model): id = models.IntegerField(primary_key = True) name = models.CharField(max_length = 80) price = models.IntegerField() class Meta: ordering = ['name'] def __str__(self): return f"{self.name}:{self.price}"
- As shown above, the URL path in urls.py will be:
path('/item/<int:nm>',Item)
Now just add a few items into the DB through the admin site.
- Now in views.py, the code to show a particular item with an id = nm will be:
def Item(request,nm): item = ItemModel.objects.get(id = nm) return HttpResponse(item)
Run the server and check for an object not present in DB, say id = 4
You will get an error message
Now we will use Django Exception Handling to handle this error. Edit the code in views.py as follows:
def Item(request,nm): try: item = ItemsModel.objects.get(id = nm) except ItemsModel.DoesNotExist: return HttpResponse('Exception: Data Not Found') return HttpResponse(item)
Notice the line “except ItemsModel.DoesNotExist“. This is where Python automatically captures the exception. You can replace the exception with one of the exceptions from the list above, and handle the same with a custom error message.
For that first import
from django.core.exceptions import *
That’s it, now we can go on and add exception we want
def Item(request,nm): try: item = ItemsModel.objects.get(id = nm) except ObjectDoesNotExist: print('Data Not Found') return HttpResponse(item)
Now run the server and search for id = 4
Similarly, we will handle other important and most used exceptions from the django.core.exceptions
Some other important Exceptions
First we will have to import the library
from django.core.exceptions import <error_name>
Lets go through the important exceptions
Field Dos Not Exist
This happens when the model field does not exist
try: Model.objects.get(<field> = '<value>') except FieldDoesNotExist: print('The Field is missing')
Multiple Objects Returned
Happens when more than one object in DB has same value for a certain field
try: Model.objects.get(<name> = '<value>') except MultipleObjectsReturned: print('More than one object with the same name are present in the Database')
View Does Not Exist
Happens when we call a view through path() in urls.py , but the view does not exist.
try: path('item/', <View>) except ViewDoesNotExist: print('The View does not exist in views.py')
Validation Error
Happens when certain information in the form data is not valid
data = form.cleaned_data['name'] if '<field_name>' not in data: raise ValidationError('This name does not exist')
Conclusion
That’s it, fellas! I do hope that this article helped increase your knowledge and understanding of Django exceptions. Do refer to the official documentation for more information.
Stay safe !! keep Learning !!
Looking at this code:
try:
... # do something
except:
raise Exception('XYZ has gone wrong...')
Even with DEBUG=True
, I don’t want this raise Exception
to give that yellow page, but it does.
I want to handle the exception by redirecting users to an error page or shows the error (give a CSS error message on the top of the page…)
How do I handle that? If I simply raise it, I will get yellow debug page (again, I don’t want certain exceptions to stop the site from functioning by showing the debug page when DEBUG=True).
How do I handle these exceptions in views.py?
Martin Thoma
118k153 gold badges591 silver badges914 bronze badges
asked Jun 5, 2012 at 1:07
5
You have three options here.
- Provide a 404 handler or 500 handler
- Catch the exception elsewhere in your code and do appropriate redirection
- Provide custom middleware with the
process_exception
implemented
Middleware Example:
class MyExceptionMiddleware(object):
def process_exception(self, request, exception):
if not isinstance(exception, SomeExceptionType):
return None
return HttpResponse('some message')
answered Jun 5, 2012 at 1:16
Josh SmeatonJosh Smeaton
47.3k24 gold badges129 silver badges164 bronze badges
2
You can raise a 404 error or simply redirect user onto your custom error page with error message
from django.http import Http404
#...
def your_view(request)
#...
try:
#... do something
except:
raise Http404
#or
return redirect('your-custom-error-view-name', error='error messsage')
- Django 404 error
- Django redirect
answered Jun 5, 2012 at 1:16
chehovchehov
1636 bronze badges
1
Another suggestion could be to use Django messaging framework to display flash messages, instead of an error page.
from django.contrib import messages
#...
def another_view(request):
#...
context = {'foo': 'bar'}
try:
#... some stuff here
except SomeException as e:
messages.add_message(request, messages.ERROR, e)
return render(request, 'appname/another_view.html', context)
And then in the view as in Django documentation:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
answered Oct 25, 2016 at 8:48
simonsimon
5301 gold badge4 silver badges14 bronze badges
If you want to get proper traceback and message as well. Then I will suggest using a custom middleware and add it to the settings.py middleware section at the end.
The following code will process the exception only in production. You may remove the DEBUG condition if you wish.
from django.http import HttpResponse
from django.conf import settings
import traceback
class ErrorHandlerMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_exception(self, request, exception):
if not settings.DEBUG:
if exception:
message = "{url}n{error}n{tb}".format(
url=request.build_absolute_uri(),
error=repr(exception),
tb=traceback.format_exc()
)
# Do whatever with the message now
return HttpResponse("Error processing the request.", status=500)
answered Jan 24, 2020 at 12:31
Django Exceptions
Django raises some of its own exceptions as well as standard Python exceptions.
Django Core Exceptions
Django core exception classes are defined in django.core.exceptions
.
AppRegistryNotReady
-
exception AppRegistryNotReady
[source] -
This exception is raised when attempting to use models before the app loading process, which initializes the ORM, is complete.
ObjectDoesNotExist
-
exception ObjectDoesNotExist
[source] -
The base class for
Model.DoesNotExist
exceptions. Atry/except
forObjectDoesNotExist
will catchDoesNotExist
exceptions for all models.See
get()
.
EmptyResultSet
-
exception EmptyResultSet
[source] -
EmptyResultSet
may be raised during query generation if a query won’t return any results. Most Django projects won’t encounter this exception, but it might be useful for implementing custom lookups and expressions.
FieldDoesNotExist
-
exception FieldDoesNotExist
[source] -
The
FieldDoesNotExist
exception is raised by a model’s_meta.get_field()
method when the requested field does not exist on the model or on the model’s parents.
MultipleObjectsReturned
-
exception MultipleObjectsReturned
[source] -
The base class for
Model.MultipleObjectsReturned
exceptions. Atry/except
forMultipleObjectsReturned
will catchMultipleObjectsReturned
exceptions for all models.See
get()
.
SuspiciousOperation
-
exception SuspiciousOperation
[source] -
The
SuspiciousOperation
exception is raised when a user has performed an operation that should be considered suspicious from a security perspective, such as tampering with a session cookie. Subclasses ofSuspiciousOperation
include:DisallowedHost
DisallowedModelAdminLookup
DisallowedModelAdminToField
DisallowedRedirect
InvalidSessionKey
RequestDataTooBig
SuspiciousFileOperation
SuspiciousMultipartForm
SuspiciousSession
TooManyFieldsSent
If a
SuspiciousOperation
exception reaches the ASGI/WSGI handler level it is logged at theError
level and results in aHttpResponseBadRequest
. See the logging documentation for more information.
PermissionDenied
-
exception PermissionDenied
[source] -
The
PermissionDenied
exception is raised when a user does not have permission to perform the action requested.
ViewDoesNotExist
-
exception ViewDoesNotExist
[source] -
The
ViewDoesNotExist
exception is raised bydjango.urls
when a requested view does not exist.
MiddlewareNotUsed
-
exception MiddlewareNotUsed
[source] -
The
MiddlewareNotUsed
exception is raised when a middleware is not used in the server configuration.
ImproperlyConfigured
-
exception ImproperlyConfigured
[source] -
The
ImproperlyConfigured
exception is raised when Django is somehow improperly configured – for example, if a value insettings.py
is incorrect or unparseable.
FieldError
-
exception FieldError
[source] -
The
FieldError
exception is raised when there is a problem with a model field. This can happen for several reasons:- A field in a model clashes with a field of the same name from an abstract base class
- An infinite loop is caused by ordering
- A keyword cannot be parsed from the filter parameters
- A field cannot be determined from a keyword in the query parameters
- A join is not permitted on the specified field
- A field name is invalid
- A query contains invalid order_by arguments
ValidationError
-
exception ValidationError
[source] -
The
ValidationError
exception is raised when data fails form or model field validation. For more information about validation, see Form and Field Validation, Model Field Validation and the Validator Reference.
NON_FIELD_ERRORS
-
NON_FIELD_ERRORS
ValidationError
s that don’t belong to a particular field in a form or model are classified as NON_FIELD_ERRORS
. This constant is used as a key in dictionaries that otherwise map fields to their respective list of errors.
BadRequest
-
exception BadRequest
[source] -
The
BadRequest
exception is raised when the request cannot be processed due to a client error. If aBadRequest
exception reaches the ASGI/WSGI handler level it results in aHttpResponseBadRequest
.
RequestAborted
-
exception RequestAborted
[source] -
The
RequestAborted
exception is raised when an HTTP body being read in by the handler is cut off midstream and the client connection closes, or when the client does not send data and hits a timeout where the server closes the connection.It is internal to the HTTP handler modules and you are unlikely to see it elsewhere. If you are modifying HTTP handling code, you should raise this when you encounter an aborted request to make sure the socket is closed cleanly.
SynchronousOnlyOperation
-
exception SynchronousOnlyOperation
[source] -
The
SynchronousOnlyOperation
exception is raised when code that is only allowed in synchronous Python code is called from an asynchronous context (a thread with a running asynchronous event loop). These parts of Django are generally heavily reliant on thread-safety to function and don’t work correctly under coroutines sharing the same thread.If you are trying to call code that is synchronous-only from an asynchronous thread, then create a synchronous thread and call it in that. You can accomplish this is with
asgiref.sync.sync_to_async()
.
URL Resolver exceptions
URL Resolver exceptions are defined in django.urls
.
Resolver404
-
exception Resolver404
-
The
Resolver404
exception is raised byresolve()
if the path passed toresolve()
doesn’t map to a view. It’s a subclass ofdjango.http.Http404
.
NoReverseMatch
-
exception NoReverseMatch
-
The
NoReverseMatch
exception is raised bydjango.urls
when a matching URL in your URLconf cannot be identified based on the parameters supplied.
Database Exceptions
Database exceptions may be imported from django.db
.
Django wraps the standard database exceptions so that your Django code has a guaranteed common implementation of these classes.
-
exception Error
[source]
-
exception InterfaceError
[source]
-
exception DatabaseError
[source]
-
exception DataError
[source]
-
exception OperationalError
[source]
-
exception IntegrityError
[source]
-
exception InternalError
[source]
-
exception ProgrammingError
[source]
-
exception NotSupportedError
[source]
The Django wrappers for database exceptions behave exactly the same as the underlying database exceptions. See PEP 249, the Python Database API Specification v2.0, for further information.
As per PEP 3134, a __cause__
attribute is set with the original (underlying) database exception, allowing access to any additional information provided.
-
exception models.ProtectedError
Raised to prevent deletion of referenced objects when using django.db.models.PROTECT
. models.ProtectedError
is a subclass of IntegrityError
.
-
exception models.RestrictedError
Raised to prevent deletion of referenced objects when using django.db.models.RESTRICT
. models.RestrictedError
is a subclass of IntegrityError
.
HTTP Exceptions
HTTP exceptions may be imported from django.http
.
UnreadablePostError
-
exception UnreadablePostError
-
UnreadablePostError
is raised when a user cancels an upload.
Sessions Exceptions
Sessions exceptions are defined in django.contrib.sessions.exceptions
.
SessionInterrupted
-
exception SessionInterrupted
[source] -
SessionInterrupted
is raised when a session is destroyed in a concurrent request. It’s a subclass ofBadRequest
.
Transaction Exceptions
Transaction exceptions are defined in django.db.transaction
.
TransactionManagementError
-
exception TransactionManagementError
[source] -
TransactionManagementError
is raised for any and all problems related to database transactions.
Testing Framework Exceptions
Exceptions provided by the django.test
package.
RedirectCycleError
-
exception client.RedirectCycleError
-
RedirectCycleError
is raised when the test client detects a loop or an overly long chain of redirects.
Python Exceptions
Django raises built-in Python exceptions when appropriate as well. See the Python documentation for further information on the Built-in Exceptions.
Django
4.1
-
django-admin and manage.py
django-admin is Django’s command-line utility for administrative tasks.
-
Commands provided by applications
Some commands are only available when the django.contrib application that implements them has been enabled.
-
The File object
The django.core.files module and its submodules contain built-in classes for basic handling The File class is thin wrapper around Python object with some
-
File handling
File handling The object class ContentFile ImageFile Additional methods files attached to objects storage API Getting current FileSystemStorage Uploaded
Until now error messages haven’t been more than mentioned, but if you have tried
out the examples you have probably seen some. There are (at least) two
distinguishable kinds of errors: syntax errors and exceptions.
8.1. Syntax Errors¶
Syntax errors, also known as parsing errors, are perhaps the most common kind of
complaint you get while you are still learning Python:
>>> while True print('Hello world') File "<stdin>", line 1 while True print('Hello world') ^ SyntaxError: invalid syntax
The parser repeats the offending line and displays a little ‘arrow’ pointing at
the earliest point in the line where the error was detected. The error is
caused by (or at least detected at) the token preceding the arrow: in the
example, the error is detected at the function print()
, since a colon
(':'
) is missing before it. File name and line number are printed so you
know where to look in case the input came from a script.
8.2. Exceptions¶
Even if a statement or expression is syntactically correct, it may cause an
error when an attempt is made to execute it. Errors detected during execution
are called exceptions and are not unconditionally fatal: you will soon learn
how to handle them in Python programs. Most exceptions are not handled by
programs, however, and result in error messages as shown here:
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> 4 + spam*3 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate str (not "int") to str
The last line of the error message indicates what happened. Exceptions come in
different types, and the type is printed as part of the message: the types in
the example are ZeroDivisionError
, NameError
and TypeError
.
The string printed as the exception type is the name of the built-in exception
that occurred. This is true for all built-in exceptions, but need not be true
for user-defined exceptions (although it is a useful convention). Standard
exception names are built-in identifiers (not reserved keywords).
The rest of the line provides detail based on the type of exception and what
caused it.
The preceding part of the error message shows the context where the exception
occurred, in the form of a stack traceback. In general it contains a stack
traceback listing source lines; however, it will not display lines read from
standard input.
Built-in Exceptions lists the built-in exceptions and their meanings.
8.3. Handling Exceptions¶
It is possible to write programs that handle selected exceptions. Look at the
following example, which asks the user for input until a valid integer has been
entered, but allows the user to interrupt the program (using Control-C or
whatever the operating system supports); note that a user-generated interruption
is signalled by raising the KeyboardInterrupt
exception.
>>> while True: ... try: ... x = int(input("Please enter a number: ")) ... break ... except ValueError: ... print("Oops! That was no valid number. Try again...") ...
The try
statement works as follows.
-
First, the try clause (the statement(s) between the
try
and
except
keywords) is executed. -
If no exception occurs, the except clause is skipped and execution of the
try
statement is finished. -
If an exception occurs during execution of the
try
clause, the rest of the
clause is skipped. Then, if its type matches the exception named after the
except
keyword, the except clause is executed, and then execution
continues after the try/except block. -
If an exception occurs which does not match the exception named in the except
clause, it is passed on to outertry
statements; if no handler is
found, it is an unhandled exception and execution stops with a message as
shown above.
A try
statement may have more than one except clause, to specify
handlers for different exceptions. At most one handler will be executed.
Handlers only handle exceptions that occur in the corresponding try clause,
not in other handlers of the same try
statement. An except clause
may name multiple exceptions as a parenthesized tuple, for example:
... except (RuntimeError, TypeError, NameError): ... pass
A class in an except
clause is compatible with an exception if it is
the same class or a base class thereof (but not the other way around — an
except clause listing a derived class is not compatible with a base class).
For example, the following code will print B, C, D in that order:
class B(Exception): pass class C(B): pass class D(C): pass for cls in [B, C, D]: try: raise cls() except D: print("D") except C: print("C") except B: print("B")
Note that if the except clauses were reversed (with except B
first), it
would have printed B, B, B — the first matching except clause is triggered.
All exceptions inherit from BaseException
, and so it can be used to serve
as a wildcard. Use this with extreme caution, since it is easy to mask a real
programming error in this way! It can also be used to print an error message and
then re-raise the exception (allowing a caller to handle the exception as well):
import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print("OS error: {0}".format(err)) except ValueError: print("Could not convert data to an integer.") except BaseException as err: print(f"Unexpected {err=}, {type(err)=}") raise
Alternatively the last except clause may omit the exception name(s), however the exception
value must then be retrieved from sys.exc_info()[1]
.
The try
… except
statement has an optional else
clause, which, when present, must follow all except clauses. It is useful
for code that must be executed if the try clause does not raise an exception.
For example:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except OSError: print('cannot open', arg) else: print(arg, 'has', len(f.readlines()), 'lines') f.close()
The use of the else
clause is better than adding additional code to
the try
clause because it avoids accidentally catching an exception
that wasn’t raised by the code being protected by the try
…
except
statement.
When an exception occurs, it may have an associated value, also known as the
exception’s argument. The presence and type of the argument depend on the
exception type.
The except clause may specify a variable after the exception name. The
variable is bound to an exception instance with the arguments stored in
instance.args
. For convenience, the exception instance defines
__str__()
so the arguments can be printed directly without having to
reference .args
. One may also instantiate an exception first before
raising it and add any attributes to it as desired.
>>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: ... print(type(inst)) # the exception instance ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses ... x, y = inst.args # unpack args ... print('x =', x) ... print('y =', y) ... <class 'Exception'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
If an exception has arguments, they are printed as the last part (‘detail’) of
the message for unhandled exceptions.
Exception handlers don’t just handle exceptions if they occur immediately in the
try clause, but also if they occur inside functions that are called (even
indirectly) in the try clause. For example:
>>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError as err: ... print('Handling run-time error:', err) ... Handling run-time error: division by zero
8.4. Raising Exceptions¶
The raise
statement allows the programmer to force a specified
exception to occur. For example:
>>> raise NameError('HiThere') Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: HiThere
The sole argument to raise
indicates the exception to be raised.
This must be either an exception instance or an exception class (a class that
derives from Exception
). If an exception class is passed, it will
be implicitly instantiated by calling its constructor with no arguments:
raise ValueError # shorthand for 'raise ValueError()'
If you need to determine whether an exception was raised but don’t intend to
handle it, a simpler form of the raise
statement allows you to
re-raise the exception:
>>> try: ... raise NameError('HiThere') ... except NameError: ... print('An exception flew by!') ... raise ... An exception flew by! Traceback (most recent call last): File "<stdin>", line 2, in <module> NameError: HiThere
8.5. Exception Chaining¶
The raise
statement allows an optional from
which enables
chaining exceptions. For example:
# exc must be exception instance or None. raise RuntimeError from exc
This can be useful when you are transforming exceptions. For example:
>>> def func(): ... raise ConnectionError ... >>> try: ... func() ... except ConnectionError as exc: ... raise RuntimeError('Failed to open database') from exc ... Traceback (most recent call last): File "<stdin>", line 2, in <module> File "<stdin>", line 2, in func ConnectionError The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Failed to open database
Exception chaining happens automatically when an exception is raised inside an
except
or finally
section. This can be
disabled by using from None
idiom:
>>> try: ... open('database.sqlite') ... except OSError: ... raise RuntimeError from None ... Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError
For more information about chaining mechanics, see Built-in Exceptions.
8.6. User-defined Exceptions¶
Programs may name their own exceptions by creating a new exception class (see
Classes for more about Python classes). Exceptions should typically
be derived from the Exception
class, either directly or indirectly.
Exception classes can be defined which do anything any other class can do, but
are usually kept simple, often only offering a number of attributes that allow
information about the error to be extracted by handlers for the exception.
Most exceptions are defined with names that end in “Error”, similar to the
naming of the standard exceptions.
Many standard modules define their own exceptions to report errors that may
occur in functions they define. More information on classes is presented in
chapter Classes.
8.7. Defining Clean-up Actions¶
The try
statement has another optional clause which is intended to
define clean-up actions that must be executed under all circumstances. For
example:
>>> try: ... raise KeyboardInterrupt ... finally: ... print('Goodbye, world!') ... Goodbye, world! KeyboardInterrupt Traceback (most recent call last): File "<stdin>", line 2, in <module>
If a finally
clause is present, the finally
clause will execute as the last task before the try
statement completes. The finally
clause runs whether or
not the try
statement produces an exception. The following
points discuss more complex cases when an exception occurs:
-
If an exception occurs during execution of the
try
clause, the exception may be handled by anexcept
clause. If the exception is not handled by anexcept
clause, the exception is re-raised after thefinally
clause has been executed. -
An exception could occur during execution of an
except
orelse
clause. Again, the exception is re-raised after
thefinally
clause has been executed. -
If the
finally
clause executes abreak
,
continue
orreturn
statement, exceptions are not
re-raised. -
If the
try
statement reaches abreak
,
continue
orreturn
statement, the
finally
clause will execute just prior to the
break
,continue
orreturn
statement’s execution. -
If a
finally
clause includes areturn
statement, the returned value will be the one from the
finally
clause’sreturn
statement, not the
value from thetry
clause’sreturn
statement.
For example:
>>> def bool_return(): ... try: ... return True ... finally: ... return False ... >>> bool_return() False
A more complicated example:
>>> def divide(x, y): ... try: ... result = x / y ... except ZeroDivisionError: ... print("division by zero!") ... else: ... print("result is", result) ... finally: ... print("executing finally clause") ... >>> divide(2, 1) result is 2.0 executing finally clause >>> divide(2, 0) division by zero! executing finally clause >>> divide("2", "1") executing finally clause Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in divide TypeError: unsupported operand type(s) for /: 'str' and 'str'
As you can see, the finally
clause is executed in any event. The
TypeError
raised by dividing two strings is not handled by the
except
clause and therefore re-raised after the finally
clause has been executed.
In real world applications, the finally
clause is useful for
releasing external resources (such as files or network connections), regardless
of whether the use of the resource was successful.
8.8. Predefined Clean-up Actions¶
Some objects define standard clean-up actions to be undertaken when the object
is no longer needed, regardless of whether or not the operation using the object
succeeded or failed. Look at the following example, which tries to open a file
and print its contents to the screen.
for line in open("myfile.txt"): print(line, end="")
The problem with this code is that it leaves the file open for an indeterminate
amount of time after this part of the code has finished executing.
This is not an issue in simple scripts, but can be a problem for larger
applications. The with
statement allows objects like files to be
used in a way that ensures they are always cleaned up promptly and correctly.
with open("myfile.txt") as f: for line in f: print(line, end="")
After the statement is executed, the file f is always closed, even if a
problem was encountered while processing the lines. Objects which, like files,
provide predefined clean-up actions will indicate this in their documentation.
exceptions.py
Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure.
— Doug Hellmann, Python Exception Handling Techniques
Exception handling in REST framework views
REST framework’s views handle various exceptions, and deal with returning appropriate error responses.
The handled exceptions are:
- Subclasses of
APIException
raised inside REST framework. - Django’s
Http404
exception. - Django’s
PermissionDenied
exception.
In each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.
Most error responses will include a key detail
in the body of the response.
For example, the following request:
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
Might receive an error response indicating that the DELETE
method is not allowed on that resource:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 42
{"detail": "Method 'DELETE' not allowed."}
Validation errors are handled slightly differently, and will include the field names as the keys in the response. If the validation error was not specific to a particular field then it will use the «non_field_errors» key, or whatever string value has been set for the NON_FIELD_ERRORS_KEY
setting.
An example validation error might look like this:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 94
{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}
Custom exception handling
You can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects. This allows you to control the style of error responses used by your API.
The function must take a pair of arguments, the first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a Response
object, or return None
if the exception cannot be handled. If the handler returns None
then the exception will be re-raised and Django will return a standard HTTP 500 ‘server error’ response.
For example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 62
{"status_code": 405, "detail": "Method 'DELETE' not allowed."}
In order to alter the style of the response, you could write the following custom exception handler:
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
# Now add the HTTP status code to the response.
if response is not None:
response.data['status_code'] = response.status_code
return response
The context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as context['view']
.
The exception handler must also be configured in your settings, using the EXCEPTION_HANDLER
setting key. For example:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
If not specified, the 'EXCEPTION_HANDLER'
setting defaults to the standard exception handler provided by REST framework:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
Note that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the HTTP_400_BAD_REQUEST
responses that are returned by the generic views when serializer validation fails.
API Reference
APIException
Signature: APIException()
The base class for all exceptions raised inside an APIView
class or @api_view
.
To provide a custom exception, subclass APIException
and set the .status_code
, .default_detail
, and default_code
attributes on the class.
For example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the «503 Service Unavailable» HTTP response code. You could do this like so:
from rest_framework.exceptions import APIException
class ServiceUnavailable(APIException):
status_code = 503
default_detail = 'Service temporarily unavailable, try again later.'
default_code = 'service_unavailable'
Inspecting API exceptions
There are a number of different properties available for inspecting the status
of an API exception. You can use these to build custom exception handling
for your project.
The available attributes and methods are:
.detail
— Return the textual description of the error..get_codes()
— Return the code identifier of the error..get_full_details()
— Return both the textual description and the code identifier.
In most cases the error detail will be a simple item:
>>> print(exc.detail)
You do not have permission to perform this action.
>>> print(exc.get_codes())
permission_denied
>>> print(exc.get_full_details())
{'message':'You do not have permission to perform this action.','code':'permission_denied'}
In the case of validation errors the error detail will be either a list or
dictionary of items:
>>> print(exc.detail)
{"name":"This field is required.","age":"A valid integer is required."}
>>> print(exc.get_codes())
{"name":"required","age":"invalid"}
>>> print(exc.get_full_details())
{"name":{"message":"This field is required.","code":"required"},"age":{"message":"A valid integer is required.","code":"invalid"}}
ParseError
Signature: ParseError(detail=None, code=None)
Raised if the request contains malformed data when accessing request.data
.
By default this exception results in a response with the HTTP status code «400 Bad Request».
AuthenticationFailed
Signature: AuthenticationFailed(detail=None, code=None)
Raised when an incoming request includes incorrect authentication.
By default this exception results in a response with the HTTP status code «401 Unauthenticated», but it may also result in a «403 Forbidden» response, depending on the authentication scheme in use. See the authentication documentation for more details.
NotAuthenticated
Signature: NotAuthenticated(detail=None, code=None)
Raised when an unauthenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code «401 Unauthenticated», but it may also result in a «403 Forbidden» response, depending on the authentication scheme in use. See the authentication documentation for more details.
PermissionDenied
Signature: PermissionDenied(detail=None, code=None)
Raised when an authenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code «403 Forbidden».
NotFound
Signature: NotFound(detail=None, code=None)
Raised when a resource does not exists at the given URL. This exception is equivalent to the standard Http404
Django exception.
By default this exception results in a response with the HTTP status code «404 Not Found».
MethodNotAllowed
Signature: MethodNotAllowed(method, detail=None, code=None)
Raised when an incoming request occurs that does not map to a handler method on the view.
By default this exception results in a response with the HTTP status code «405 Method Not Allowed».
NotAcceptable
Signature: NotAcceptable(detail=None, code=None)
Raised when an incoming request occurs with an Accept
header that cannot be satisfied by any of the available renderers.
By default this exception results in a response with the HTTP status code «406 Not Acceptable».
Signature: UnsupportedMediaType(media_type, detail=None, code=None)
Raised if there are no parsers that can handle the content type of the request data when accessing request.data
.
By default this exception results in a response with the HTTP status code «415 Unsupported Media Type».
Throttled
Signature: Throttled(wait=None, detail=None, code=None)
Raised when an incoming request fails the throttling checks.
By default this exception results in a response with the HTTP status code «429 Too Many Requests».
ValidationError
Signature: ValidationError(detail, code=None)
The ValidationError
exception is slightly different from the other APIException
classes:
- The
detail
argument is mandatory, not optional. - The
detail
argument may be a list or dictionary of error details, and may also be a nested data structure. By using a dictionary, you can specify field-level errors while performing object-level validation in thevalidate()
method of a serializer. For example.raise serializers.ValidationError({'name': 'Please enter a valid name.'})
- By convention you should import the serializers module and use a fully qualified
ValidationError
style, in order to differentiate it from Django’s built-in validation error. For example.raise serializers.ValidationError('This field must be an integer value.')
The ValidationError
class should be used for serializer and field validation, and by validator classes. It is also raised when calling serializer.is_valid
with the raise_exception
keyword argument:
serializer.is_valid(raise_exception=True)
The generic views use the raise_exception=True
flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.
By default this exception results in a response with the HTTP status code «400 Bad Request».
Generic Error Views
Django REST Framework provides two error views suitable for providing generic JSON 500
Server Error and
400
Bad Request responses. (Django’s default error views provide HTML responses, which may not be appropriate for an
API-only application.)
Use these as per Django’s Customizing error views documentation.
rest_framework.exceptions.server_error
Returns a response with status code 500
and application/json
content type.
Set as handler500
:
handler500 = 'rest_framework.exceptions.server_error'
rest_framework.exceptions.bad_request
Returns a response with status code 400
and application/json
content type.
Set as handler400
:
handler400 = 'rest_framework.exceptions.bad_request'
Third party packages
The following third-party packages are also available.
DRF Standardized Errors
The drf-standardized-errors package provides an exception handler that generates the same format for all 4xx and 5xx responses. It is a drop-in replacement for the default exception handler and allows customizing the error response format without rewriting the whole exception handler. The standardized error response format is easier to document and easier to handle by API consumers.