Как многим известно, Django из коробки принуждает использовать рекомендацию по добавлению слэша (/) в конце пути URL, что нравится далеко не всем. Я лично нахожу это устаревшей SEO практикой, которая абсолютно потеряла свой смысл, и хоть как-то влиет на релеватность поисковой выдачи. Поисковые алгоритмы за эти десятилетия изменились кардинально, а добровольно-принудительная практика добавления слэша в конце пути URL в Django осталась. Да и в целом мне просто это не нравится практически и эстетически. Так уж сложилась практика ввода адреса URL, что данный слэш никому не нужен от слова совсем.
Сам фреймворк Django разрешает не использовать завершающий слэш в пути URL, если вы будете писать маршруты соответствующим образом, т.е. просто ставить слэш, где он вам нужен, а не каждый раз в конце его маршрута. Но если использовать коробочные решения, вроде django-debug-toolbar или django.contrib.admin, где все маршруты уже прописаны за вас, то там слэш будет явно и жестко добавлен в конце каждого маршрута, и избавиться от него каким-то параметром конфига нельзя, потому что такого конфига просто нет.
Существующие официальное решение по избавлению от завершающего слэша через APPEND_SLASH для django-debug-toolbar или django.contrib.admin в пути URL полностью проблему не решают. Конфигурационный параметр APPEND_SLASH может только включать или отключать редирект, если путь URL был передан без завершающего слэша. В купе с Nginx и APPEND_SLASH = False можно добиться работы без завершающего слэша, но создание/генерация маршрутов внутри приложения по-прежнему будут его добавлять, а нам-то нужно, чтобы его не было везде. Единственное решение, которое я нашел для себя обоснованным, это тупо пересоздать маршруты без завершиющего слэша, где этот слэш был добавлен. Решение, возможно, не самое лучшее, но задачу выполняет. Другого я, к сожалению, найти не смог. Собственно, решение изложено ниже.
Первое и самое необходимое, нам нужно установить параметр APPEND_SLASH в значение False, чтобы роутинг Django не добавлял завершающий слэш в конец пути URL.
# djangoproject/settings.py
APPEND_SLASH = False
Второе и последнее, точечно переписать маршруты, которые содержат завершающий слэш. В моем примере учитываются только пакет django-debug-toolbar и приложение django.contrib.admin. Если вы используете еще что-то, то возможно потребуется внести правки в сниппет, т.к. данное решение не универсальное, а заточено только под вышесказанное.
# djangoproject/urls.py
from django.contrib import admin
from django.urls import path
from django.urls.resolvers import RoutePattern, RegexPattern, URLPattern, URLResolver
from django.conf import settings
def _make_no_trailing_slash_pattern(pattern, prefix='/'):
if isinstance(pattern, RoutePattern):
route: str = pattern._route.strip('/')
if route != '':
route = prefix + route
return RoutePattern(route, pattern.name, pattern._is_endpoint)
elif isinstance(pattern, RegexPattern):
regex: str = pattern._regex.strip('/')
if regex.startswith('^'):
regex = '^' + prefix + regex.removeprefix('^')
else:
regex = prefix + regex
if regex.endswith('/$'):
regex = regex.removesuffix('/$') + '$'
return RegexPattern(regex, pattern.name, pattern._is_endpoint)
else:
raise ValueError('The pattern type of "' + type(pattern).__name__ + '" is not supported.')
def _make_no_trailing_slash_urls(urls, is_root=True):
if not isinstance(urls, list):
return urls
result = []
for url in urls:
if isinstance(url, URLPattern):
result.append(
URLPattern(
_make_no_trailing_slash_pattern(url.pattern, '' if is_root else '/'),
url.callback,
url.default_args,
url.name,
)
)
elif isinstance(url, URLResolver):
result.append(
URLResolver(
_make_no_trailing_slash_pattern(url.pattern, '' if is_root else '/'),
_make_no_trailing_slash_urls(url.url_patterns, False),
url.default_kwargs,
url.app_name,
url.namespace,
)
)
else:
raise ValueError('The route type of "' + type(url).__name__ + '" is not supported.')
return result
urlpatterns = [
path(
'admin',
[_make_no_trailing_slash_urls(admin.site.urls[0], False), *admin.site.urls[1:]],
),
]
if settings.ENABLE_DEBUG_TOOLBAR:
from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns += _make_no_trailing_slash_urls(debug_toolbar_urls())
# Ваши маршруты приложения.
urlpatterns += [
path('yourapp', include('yout.app.urls')),
]
Я буду стараться актуализировать данный сниппет какое-то время, пока у меня будет такая возможность. На текущий момент он протестирован под django==6.0.2 и django-debug-toolbar==6.2.0.