I'm trying to define a re_path in Django that catches all URLs except those that start with /admin/. My goal is to redirect unknown URLs to a custom view (RedirectView), while ensuring that all admin URLs (including subpaths like /admin/mymodel/something/) are excluded.
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"),
]
Issue:
URLs like localhost:8000/admin/mymodel/something/ are correctly ignored, which is good.
However, single-segment URLs like localhost:8000/something/ are not being matched, even though they should be redirected.
The new_pattern
below might do the trick:
PATTERNS
original_pattern = r"^.*/(?!admin/$)[^/]+/$"
new_pattern = r"^[^/]*/(?!admin/)(?:[^/\n]+/)+$"
Demo to original_pattern: https://regex101.com/r/fp5aYg/1
Demo to new_pattern: https://regex101.com/r/2AWQcK/5
NOTES
The new_pattern
can start with any non-forward slash characters or no characters.
First forward slash /
must not be followed by admin/
.
Each forward slash /
must be followed by at least one or more non-forward slash characters [^/]+
followed by a forward slash /
: /([^/]+/)+
.
The string MUST end in a forward slash /$
.
There must be at least two forward slashes in the string separated by a non-forward slash character.
For example, the match will not match strings with two consecutive forward slashes like these: //something//something//
, or something/something//something
^[^/]*
Start at the beginning of the string. Capture 0 or more non-forward slash characters [^/]
,
i.e. match everything before the first forward slash /
.
/
the first forward slash.
(?!admin/)
The first slash cannot be followed by admin/
(?:...)+
Non-capturing group (?:...)
that repeats 1 or more times (+
).
[^/\n]+
Capture any non-forward slash [^/]
, non-newline \n
character 1 or more times. (Note: I had to ad the newline character \n
to get the multi-line demo to work correctly.)
[^/\n]+/
A non-forward slash character strings are followed by one forward slash /
.
$
End of string $
follows the second or later forward slash /$
.
TEST STRINGS:
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/
MATCHES:
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/
NON-MATCHES:
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