Использование 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:
- r"https?[-a-zA-Z0-9%._+~#=]+"
r"https?[%23A](www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)(?=\/foo)"
https://regexr.com/6ue7b .
- r"(https?://(www.)?)?[-a-zA-Z0-9@:%.+~#=]{2,256}(.[a-z]{2,6})?\b([-a-zA-Z0-9@:%+.~#?&//=]*)
Если я правильно понимаю вашу проблему, похоже, что вы пытаетесь получить соответствие 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
Вы получаете эту ошибку:
(Я выделил соответствующую часть красным цветом.)
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