Skip to content

Commit a6dc141

Browse files
committed
Use atomic increment for nr_times_visited
1 parent 6fba262 commit a6dc141

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

regex_redirects/middleware.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import re
2+
import logging
23

34
from django import http
45
from django.conf import settings
56
from django.core.cache import cache
67
from django.core.exceptions import ImproperlyConfigured
8+
from django.db import transaction
9+
from django.db.models.expressions import F
10+
11+
logger = logging.getLogger(__name__)
712

813
from .models import Redirect
914

@@ -34,9 +39,19 @@ def __init__(self, *args, **kwargs):
3439
super(RedirectFallbackMiddleware, self).__init__(*args, **kwargs)
3540

3641
def increment_redirect(self, pk):
37-
redirect = Redirect.objects.get(pk=pk)
38-
redirect.nr_times_visited += 1
39-
redirect.save()
42+
def increment():
43+
try:
44+
Redirect.objects.filter(pk=pk).update(
45+
nr_times_visited=F("nr_times_visited") + 1
46+
)
47+
except Exception:
48+
logger.warning("Increment nr_times_visited failed.")
49+
raise
50+
51+
# https://docs.djangoproject.com/en/5.1/topics/db/transactions/#performing-actions-after-commit
52+
# All errors derived from Python’s Exception class are caught and logged to the
53+
# django.db.backends.base logger.
54+
transaction.on_commit(increment)
4055

4156
def process_response(self, request, response):
4257
if response.status_code != 404:

regex_redirects/tests.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ def test_model(self):
2222
def test_redirect(self):
2323
redirect = Redirect.objects.create(old_path="/initial", new_path="/new_target")
2424
self.assertEqual(redirect.nr_times_visited, 0)
25-
response = self.client.get("/initial")
25+
with self.captureOnCommitCallbacks(execute=True) as callbacks:
26+
response = self.client.get("/initial")
27+
self.assertEqual(len(callbacks), 1)
2628
self.assertRedirects(
2729
response, "/new_target", status_code=301, target_status_code=404
2830
)
@@ -35,7 +37,9 @@ def test_redirect_with_append_slash(self):
3537
old_path="/initial/", new_path="/new_target/"
3638
)
3739
self.assertEqual(redirect.nr_times_visited, 0)
38-
response = self.client.get("/initial")
40+
with self.captureOnCommitCallbacks(execute=True) as callbacks:
41+
response = self.client.get("/initial")
42+
self.assertEqual(len(callbacks), 1)
3943
self.assertRedirects(
4044
response, "/new_target/", status_code=301, target_status_code=404
4145
)
@@ -51,12 +55,14 @@ def test_redirect_with_append_slash_and_query_string(self):
5155
)
5256

5357
def test_regular_expression(self):
54-
redirect = Redirect.objects.create(
58+
Redirect.objects.create(
5559
old_path=r"/news/index/(\d+)/(.*)/",
5660
new_path="/my/news/$2/",
5761
regular_expression=True,
5862
)
59-
response = self.client.get("/news/index/12345/foobar/")
63+
with self.captureOnCommitCallbacks(execute=True) as callbacks:
64+
response = self.client.get("/news/index/12345/foobar/")
65+
self.assertEqual(len(callbacks), 1)
6066
self.assertRedirects(
6167
response, "/my/news/foobar/", status_code=301, target_status_code=404
6268
)

testsettings.py

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
SITE_ID = 1
2424

25+
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
26+
2527
# Django seems to require a ROOT_URLCONF.
2628
ROOT_URLCONF = __name__
2729
urlpatterns = []

0 commit comments

Comments
 (0)