Django re_path для перехвата всех URL-адресов, кроме /admin/, не работает должным образом

Я пытаюсь определить re_path в Django, который перехватывает все URL-адреса, кроме тех, которые начинаются с /admin/. Моя цель - перенаправить неизвестные URL-адреса в пользовательское представление (RedirectView), гарантируя при этом, что все URL-адреса администратора (включая подпути, такие как /admin/mymodel/something/) будут исключены.

from django.urls import re_path, path
from django.contrib import admin
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),  # Ensure Django admin URLs are handled
]

# Catch-all pattern that should exclude /admin/ URLs
urlpatterns += [
    re_path(r"^.*/(?!admin/$)[^/]+/$", views.RedirectView.as_view(), name="my-view"),
]

Проблема:

URL-адреса, подобные localhost:8000/admin/mymodel/something/, корректно игнорируются, что хорошо.

Однако односегментные URL-адреса, такие как localhost:8000/что-то/, не совпадают, хотя они должны быть перенаправлены.

измените свой re_path, который должен исключать /admin/ URL-адреса

    urlpatterns += [
    re_path(r"^(?!admin/).*", views.RedirectView.as_view(), name="my-view"),
]

Моя цель - перенаправить неизвестные URL-адреса в пользовательское представление (RedirectView), гарантируя при этом, что все URL-адреса администратора (включая подпути, такие как /admin/mymodel/something/) будут исключены.

Хорошая новость в том, что Django сопоставляет пути сверху вниз. Поэтому, если путь равен admin/…, сначала он будет искать admin.site.urls. Если вы не установите для атрибута .final_catch_all_view [Django-doc] сайта администратора значение False, он будет содержать сводный список, который, таким образом, будет обрабатывать все пути с code/.

Таким образом, вы можете использовать сводный список с:

from django.contrib import admin
from django.urls import path, re_path

from . import views

urlpatterns = [
    path('admin/', admin.site.urls),  # Ensure Django admin URLs are handled
]
urlpatterns += [
    re_path(r'\A.*/\Z', views.RedirectView.as_view(), name='my-view'),
]

Я бы также добавил завершающую косую черту, чтобы логика Django APPEND_SLASH [Django-doc] сначала позволила выполнить некоторую работу, если в пути нет завершающей косой черты. Но если нет, вы можете удалить это.

Приведенный ниже new_pattern может помочь:

УЗОРЫ

original_pattern = r"^.*/(?!admin/$)[^/]+/$"

new_pattern = r"^[^/]*/(?!admin/)(?:[^/\n]+/)+$"

Демонстрация к оригинальному шаблону: https://regex101.com/r/fp5aYg/1

Демонстрация для new_pattern: https://regex101.com/r/2AWQcK/5

ПРИМЕЧАНИЯ

new_pattern может начинаться с любых символов, кроме косой черты, или вообще без символов. За первой косой чертой / не должно следовать admin/. За каждой прямой косой чертой / должен следовать, по крайней мере, один или несколько символов, отличных от прямой косой черты [^/]+ за которыми следует прямая косая черта /: /([^/]+/)+. Строка ДОЛЖНА заканчиваться прямой косой чертой /$. В строке должно быть не менее двух прямых косых черт, разделенных символом, отличным от прямой косой черты. Например, совпадение не будет соответствовать строкам с двумя последовательными косыми чертами, такими как эти: //something//something//, или something/something//something

  • ^[^/]* Начните с начала строки. Введите 0 или более символов без косой черты [^/], т.е. сопоставьте все символы до первой косой черты /.

  • / первая косая черта.

  • (?!admin/) За первой косой чертой не может следовать admin/

  • (?:...)+ Группа без захвата (?:...), которая повторяется 1 или более раз (+).

  • [^/\n]+ Вводите любой символ, не заканчивающийся косой чертой [^/], не переводящий строку \n, 1 или более раз. (Примечание: Мне пришлось добавить символ новой строки \n, чтобы многострочная демонстрация работала корректно.)

  • [^/\n]+/ За строками символов без прямой косой черты следует одна прямая косая черта /.

  • $ Конец строки $ следует за второй или более поздней косой чертой /$.

ТЕСТОВЫЕ СТРОКИ:

localhost:8000/admin/mymodel/something/
localhost:8000/something
localhost:8000/something/
localhost:8000/something/something/something/
localhost:8000
something/
/someting/a/
/someting//a/a/
/someting//
/someting//something//
/someting/something//
/someting//something//
something/something/
something/admin/something/
/something/admin/something/
/admin/
/admin/green/yellow/
/admin/hello/
/admin/hello/hello/
/admin/hello/hello/hello/
/admin/hello/hello
admin/green/yellow/
admin/hello/
admin/
/notadmin/path/something/
/notadmin/path/something
/something/admin/something/
/what/is/happening/
/no_admin/yellow/
/no_admin/yellow/green/red/

СОВПАДЕНИЯ:

localhost:8000/something/
localhost:8000/something/something/something/
/someting/a/
something/something/
/something/admin/something/
admin/green/yellow/
admin/hello/
/something/admin/something/
/what/is/happening/
/no_admin/yellow/
/no_admin/yellow/green/red/

НЕСООТВЕТСТВИЯ:

localhost:8000/admin/mymodel/something/
localhost:8000/something
localhost:8000
something/
/someting//a/a/
/someting//
/someting//something//
/someting/something//
/someting//something//
something/admin/something/
/admin/
/admin/green/yellow/
/admin/hello/
/admin/hello/hello/
/admin/hello/hello/hello/
/admin/hello/hello
admin/
/notadmin/path/something
Вернуться на верх