Skip to content

Commit 9de554b

Browse files
committed
Use django.db.models.functions.Replace (from 2.2) for exact redirect
`Replace` allows us to modify a field in the row. We use it to remove the `$rest` part of the URL and be able to compare the beginning of the from URL (without the `$rest`) against the `full_path`.
1 parent ca3f3f9 commit 9de554b

File tree

2 files changed

+18
-0
lines changed

2 files changed

+18
-0
lines changed

readthedocs/redirects/querysets.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
from readthedocs.core.utils.extend import SettingsOverrideObject
77

8+
from .vendor import Replace
9+
810

911
class RedirectQuerySetBase(models.QuerySet):
1012

@@ -37,6 +39,11 @@ def get_redirect_path_with_status(self, path, full_path=None, language=None, ver
3739
full_path,
3840
output_field=CharField(),
3941
),
42+
# This ``Replace`` could be slow if there too many redirects
43+
from_url_without_rest__startswith=Replace(
44+
'from_url',
45+
Value('$rest'),
46+
),
4047
)
4148
prefix = Q(
4249
redirect_type='prefix',
@@ -50,6 +57,7 @@ def get_redirect_path_with_status(self, path, full_path=None, language=None, ver
5057
Q(
5158
redirect_type='exact',
5259
from_url__endswith='$rest', # Python implementation does "in"
60+
full_path__startswith=F('from_url_without_rest__startswith'),
5361
) | Q(
5462
redirect_type='exact',
5563
full_path__iexact=F('from_url'),

readthedocs/redirects/vendor.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from django.db.models.expressions import Func, Value
2+
3+
4+
# This function is available on Django 2.1
5+
# We are copying it here and can be removed once we migrate to Django 2.2
6+
class Replace(Func):
7+
function = 'REPLACE'
8+
9+
def __init__(self, expression, text, replacement=Value(''), **extra):
10+
super().__init__(expression, text, replacement, **extra)

0 commit comments

Comments
 (0)