Reverse('rest_framework:login', current_app=request.resolver_match.namespace) возвращает странный путь
Я работаю над Django Rest Framework API. Я столкнулся с проблемой в моем проекте, где я продолжаю получать следующую ошибку:
django.urls.exceptions.NoReverseMatch: Reverse for 'login' with no arguments not found. 2 pattern(s) tried: ['(?P<version>[v1]+)/auth/login(?P<format>\\.[a-z0-9]+/?)\\Z', '(?P<version>[v1
]+)/auth/login/\\Z']
Эта ошибка очень странная, потому что в моем классе urls.py я использовал следующий шаблон:
re_path(r'(?P<version>[v1]+)/auth/', include('rest_framework.urls'))
Я посмотрел на файл rest_framework/urls.py, вот код внутри него:
from django.contrib.auth import views
from django.urls import path
app_name = 'rest_framework'
urlpatterns = [
path('login/', views.LoginView.as_view(template_name='rest_framework/login.html'), name='login'),
path('logout/', views.LogoutView.as_view(), name='logout'),
Итак, я понятия не имел, почему два шаблона, опробованные решателем, были
- '(?P[v1]+)/auth/login(?P\.[a-z0-9]+/?)\Z'
- '(?P[v1]+)/auth/login/\Z'
поскольку путь в rest_framework/urls.py - это просто 'login/', а не 'login(?\.[a-z0-9]+/?\z' или последнее.
Для того чтобы воспроизвести ошибку, я создал новый простой DRF API: views.py:
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
@api_view(['GET'])
def root(request, format=None):
return Response({
'/': reverse('root', request=request, format=None),
'login': reverse('rest_framework:login', current_app=request.resolver_match.namespace),
})
urls.py:
from django.urls import re_path, include
from demo.views import root
urlpatterns = [
re_path(r'', root, name='root'),
re_path(r'/auth/', include('rest_framework.urls')),
]
Когда я отправил GET-запрос на /, я получил следующий ответ:
HTTP 200 OK
Allow: GET, OPTIONS
Content-Type: application/json
Vary: Accept
{
"/": "http://18346ef2-eed4-4627-8911-7cd11a88eed2.id.repl.co/",
"login": "/%2Fauth/login/"
}
Реакция действительно странная. Первый вызов reverse() сработал нормально, но не второй. Я понятия не имею почему, но надеюсь, что знание причины поможет мне хотя бы выяснить причину проблемы в моем проекте
.
Вот ссылка на полную версию демонстрации на replit: https://replit.com/@HadilBader/demo#
ваш путь -
re_path(r'(?P<version>[v1]+)/auth/', include('rest_framework.urls'))
, которому нужен один аргумент: version. Поскольку вы объявляете его в качестве аргумента, вам нужно передавать его везде, где вам нужно обратить url, что-то вроде:
reverse(
'rest_framework:login',
current_app=request.resolver_match.namespace,
kwargs={'version': 'v1'}
)