You can use retry()
below to retry a view 0 or more times with 0 or more interval seconds:
# "store/views.py"
from django.db import DatabaseError, transaction, IntegrityError
from time import sleep
from .models import Person
from django.http import HttpResponse
def retry(count, interval=1):
def _retry(func):
def core(*args, **kwargs):
nonlocal count
if callable(count):
count = 2
for _ in range(count+1):
try:
return func(*args, **kwargs)
except DatabaseError as e:
print(e)
sleep(interval)
return core
if callable(count):
return _retry(count)
return _retry
# ...
For example, I have Person
model below. *I use PostgreSQL:
# "store/models.py"
class Person(models.Model):
name = models.CharField(max_length=30)
Then, test()
view with @retry(4, 2)
below can retry 4 times with 2 interval seconds in addition to a normal try each time IntegrityError
exception occurs as shown below:
# "store/views.py"
from django.db import DatabaseError, transaction, IntegrityError
from time import sleep
from .models import Person
from django.http import HttpResponse
def retry(count, interval=1):
# ...
@retry(4, 2) # Here
@transaction.atomic
def test(request):
qs = Person.objects.get(name="John")
qs.name = "David"
qs.save()
raise IntegrityError("Exception occurs")
return HttpResponse("Test")
As you can see, test
view is retried 4 times in addition to a normal try, then finally ValueError
exception occurs because None
is returned:
Exception occurs # Normal try
Exception occurs # 1st retry
Exception occurs # 2nd retry
Exception occurs # 3rd retry
Exception occurs # 4th retry
Internal Server Error: /store/test/
Traceback (most recent call last):
File "C:\Users\kai\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\kai\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\base.py", line 188, in _get_response
self.check_response(response, callback)
File "C:\Users\kai\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\base.py", line 309, in check_response
raise ValueError(
ValueError: The view store.views.core didn't return an HttpResponse object. It returned None instead.
[28/Dec/2022 16:42:41] "GET /store/test/ HTTP/1.1" 500 88950
And, transaction is run 5 times (The light blue one is a normal try and the yellow ones are 4 retries) according to the PostgreSQL query logs below. *You can check how to log PostgreSQL queries:

Be careful, if the order of the decorators is @transaction.atomic
then @retry(4, 2)
as shown below:
# "store/views.py"
# ...
@transaction.atomic # Here
@retry(4, 2) # Here
def test(request):
# ...
The error below occurs:
store.models.Person.DoesNotExist: Person matching query does not exist.
So, the order of the decorators must be @retry(4, 2)
then @transaction.atomic
as shown below:
# "store/views.py"
# ...
@retry(4, 2) # Here
@transaction.atomic # Here
def test(request):
# ...
And by default, @retry
retries test()
view 2 times with 1 interval second in addition to a normal try each time IntegrityError
exception occurs as shown below:
# "store/views.py"
# ...
@retry # Here
@transaction.atomic
def test(request):
# ...
As you can see, test
view is retried 2 times in addition to a normal try, then finally ValueError
exception occurs because None
is returned:
Exception occurs # Normal try
Exception occurs # 1st retry
Exception occurs # 2nd retry
Internal Server Error: /store/test/
Traceback (most recent call last):
File "C:\Users\kai\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\kai\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\base.py", line 188, in _get_response
self.check_response(response, callback)
File "C:\Users\kai\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\base.py", line 309, in check_response
raise ValueError(
ValueError: The view store.views.core didn't return an HttpResponse object. It returned None instead.
[28/Dec/2022 19:08:07] "GET /store/test/ HTTP/1.1" 500 88950
And, transaction is run 3 times (The light blue one is a normal try and the yellow ones are 2 retries) according to the PostgreSQL query logs below:

In addition, if you want to retry test()
view 3 times with 0.5 interval seconds by default with @retry
, you need to change count = 2
to count = 3
and interval=1
to interval=0.5
respectively as shown below:
# "store/views.py"
# ...
# ↓ Here
def retry(count, interval=0.5):
def _retry(func):
def core(*args, **kwargs):
nonlocal count
if callable(count):
count = 3 # <= Here
for _ in range(count+1):
try:
return func(*args, **kwargs)
except DatabaseError as e:
print(e)
sleep(interval)
return core
if callable(count):
return _retry(count)
return _retry