Использование Escaped url в Django url regex mismatch

Я пытаюсь использовать экранированный url в качестве переменной re_path для идентификатора объекта в моем API. Логика для подключения экранированного url к объекту есть, но я не могу понять, почему regex не соответствует.

В моей голове, запрос GET со следующим url /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo должен быть разобран на obj = 'http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1' и field = 'foo' для дальнейшей обработки. В конечном итоге, возвращая объект и 200. Однако я получаю 404 с очень специфической ошибкой Django, которая разрастается только тогда, когда Django бесплодно перебирает все доступные пути.

<HttpResponseNotFound status_code=404, "text/html">
(Pdb) response.content
b'\n<!doctype html>\n<html lang="en">\n<head>\n  <title>Not Found</title>\n</head>\n<body>\n  <h1>Not Found</h1><p>The requested resource was not found on this server.</p>\n</body>\n</html>\n'

Я знаю, что путь существует, так как когда я исследую urlpatterns, путь присутствует:

(Pdb) pp object_router.get_urls()
[
    ...
    <URLPattern '^(?P<obj>https?[-a-zA-Z0-9%._\+~#=]+)/(?P<field>foo|bar)\/?$' [name='test-detail-foobar']>
]

Урл экранируется с помощью urllib.parse.quote(obj.url, safe="")

Regexs tried:

Если я правильно понимаю вашу проблему, похоже, что вы пытаетесь получить соответствие regex и немедленно отправить запрос на полученный url?

Если это так, вы отправляете запрос на неправильно отформатированный url. Первый regex, который вы опубликовали, выглядит так, как будто он отлично работает для получения результата, который вы просите, однако он приводит к url, который все еще закодирован .

Вам необходимо "снять кавычки" с url перед выполнением запроса.

import re
from urllib.parse import unquote

path = '/objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo'

resp = re.search("https?[-a-zA-Z0-9%._+~#=]+", path)
url = resp[0]
print(url)
print(unquote(url))

приводит и выводит:

http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1

http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1

Рассмотрим простой проект, например, такой:

urls.py

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

urlpatterns = [
    re_path(r"https?[-a-zA-Z0-9%._+~#=]+", views.test, name="test"),
    path('admin/', admin.site.urls),
]

views.py

from django.http import HttpResponse

def test(request, obj, field):
    print(f"The object is {obj}")
    print(f"The field is {field}")
    return HttpResponse("Test test")

При посещении следующего URL: /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo

Вы получаете эту ошибку:

URL error page (Я выделил соответствующую часть красным цветом.)

Django автоматически декодирует закодированный URL и только потом применяет соответствие regex. objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo становится objects/http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1/foo. Вам придется написать эквивалентное выражение regex, которое будет соответствовать декодированному URL.

Сработает что-то вроде этого:

urls.py

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

urlpatterns = [
    re_path(r"(?P<obj>https?:\/\/.*\?id=[\d\w-]+)\/(?P<field>foo|bar)", views.test, name="test"),
    path('admin/', admin.site.urls),
]

views.py

from django.http import HttpResponse

def test(request, obj, field):
    print(f"The object is {obj}")
    print(f"The field is {field}")
    return HttpResponse("Test test")

При посещении URL /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo в консоль будет выведено следующее:

The object is http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1 
The field is foo
Вернуться на верх