使用dj-rest-auth时password_reset_confirm路由匹配失败问题求助
问题描述
调用dj-rest-auth的password/reset接口提交邮箱后触发NoReverseMatch错误,提示找不到password_reset_confirm视图或路由名。查看虚拟环境中dj-rest-auth的urls.py,发现对应的路由实际名为rest_password_reset_confirm,怀疑是包的问题。
错误信息
NoReverseMatch at /api/dj-rest-auth/password/reset/ Reverse for 'password_reset_confirm' not found. 'password_reset_confirm' is not a valid view function or pattern name. Request Method: POST Request URL: http://127.0.0.1:8000/api/dj-rest-auth/password/reset/ Django Version: 4.2.6 Exception Type: NoReverseMatch Exception Value: Reverse for 'password_reset_confirm' not found. 'password_reset_confirm' is not a valid view function or pattern name. Exception Location: /Users/coding/Projects/django/user_template_api/.venv/lib/python3.12/site-packages/django/urls/resolvers.py, line 828, in _reverse_with_prefix Raised during: dj_rest_auth.views.PasswordResetView Python Executable: /Users/coding/Projects/django/user_template_api/.venv/bin/python3 Python Version: 3.12.0 Python Path: ['/Users/coding/Projects/django/user_template_api/backend', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python312.zip', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/lib-dynload', '/Users/coding/Projects/django/user_template_api/.venv/lib/python3.12/site-packages'] Server time: Wed, 18 Oct 2023 01:59:54 +0000
相关配置文件
accounts/urls.py
from django.urls import include, path from rest_framework import routers from .views import CustomUserViewSet from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, ) router = routers.DefaultRouter() router.register(r'users', CustomUserViewSet) urlpatterns = [ path('', include(router.urls)), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path('dj-rest-auth/', include('dj_rest_auth.urls')), path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')), ]
settings.py
""" Django settings for backend project. Generated by 'django-admin startproject' using Django 4.2.1. For more information on this file, see https://docs.djangoproject.com/en/4.2/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.2/ref/settings/ """ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-$!z5s1dryft$&tjajmulo+kb7^vi$mfujnzor$_zi(7qv9jxwj' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', #3rd Party 'rest_framework', 'rest_framework_simplejwt', 'dj_rest_auth', 'allauth', 'allauth.account', 'allauth.socialaccount', 'dj_rest_auth.registration', #local 'accounts.apps.AccountsConfig', ] SITE_ID = 1 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'backend.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.request', ], }, }, ] EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" WSGI_APPLICATION = 'backend.wsgi.application' # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = 'static/' # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' AUTH_USER_MODEL = "accounts.CustomUser" REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": [ "rest_framework.permissions.IsAuthenticated", ], "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.SessionAuthentication", 'rest_framework_simplejwt.authentication.JWTAuthentication', ], 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10 } REST_AUTH = { 'TOKEN_MODEL': None, 'USE_JWT': True, 'JWT_AUTH_COOKIE': 'my-app-auth', 'JWT_AUTH_REFRESH_COOKIE': 'my-refresh-token', }
虚拟环境中dj-rest-auth的urls.py
from django.urls import path from dj_rest_auth.app_settings import api_settings from dj_rest_auth.views import ( LoginView, LogoutView, PasswordChangeView, PasswordResetConfirmView, PasswordResetView, UserDetailsView, ) urlpatterns = [ # URLs that do not require a session or valid token path('password/reset/', PasswordResetView.as_view(), name='rest_password_reset'), path('password/reset/confirm/', PasswordResetConfirmView.as_view(), name='rest_password_reset_confirm'), path('login/', LoginView.as_view(), name='rest_login'), # URLs that require a user to be logged in with a valid session / token. path('logout/', LogoutView.as_view(), name='rest_logout'), path('user/', UserDetailsView.as_view(), name='rest_user_details'), path('password/change/', PasswordChangeView.as_view(), name='rest_password_change'), ] if api_settings.USE_JWT: from rest_framework_simplejwt.views import TokenVerifyView from dj_rest_auth.jwt_auth import get_refresh_view urlpatterns += [ path('token/verify/', TokenVerifyView.as_view(), name='token_verify'), path('token/refresh/', get_refresh_view().as_view(), name='token_refresh'), ]
解决方案
这不是dj-rest-auth的bug,问题出在allauth的默认配置逻辑上:PasswordResetView生成重置链接时,默认会调用django-allauth的password_reset_confirm路由,但你只配置了dj-rest-auth的路由,未处理这个匹配关系。
有两种可行的解决方式:
方式1:指定dj-rest-auth的重置确认路由
在settings.py的REST_AUTH配置中,添加PASSWORD_RESET_CONFIRM_URL参数,指定使用dj-rest-auth自身的路由名或完整URL模板:
REST_AUTH = { 'TOKEN_MODEL': None, 'USE_JWT': True, 'JWT_AUTH_COOKIE': 'my-app-auth', 'JWT_AUTH_REFRESH_COOKIE': 'my-refresh-token', # 直接使用路由名 'PASSWORD_RESET_CONFIRM_URL': 'rest_password_reset_confirm', # 或者带参数的完整URL模板(二选一即可) # 'PASSWORD_RESET_CONFIRM_URL': '/api/dj-rest-auth/password/reset/confirm/{uid}/{token}/', }
方式2:添加allauth的全套路由(不推荐,除非需要allauth的其他功能)
在项目根urls.py中添加allauth的路由:
from django.urls import include, path urlpatterns = [ # ... 其他已有路由 path('accounts/', include('allauth.urls')), ]
验证
修改配置后重新调用password/reset接口,查看控制台输出的重置链接,应该会指向rest_password_reset_confirm对应的URL,不再触发路由不存在的错误。
内容的提问来源于stack exchange,提问作者Ash Gharibyan
相关产品推荐
相关产品推荐

