I am using Django's default password reset views and forms to send an email to the user for them to reset their password via a link in the email. I have most of the development complete but am stuck on one issue. When I receive the email from the local host, I click the link, enter my new password 2 times, hit 'submit' and get this error: Error Message.
Below is my code.
urls.py
"""defines URL patterns for users"""
from django.urls import path, include, reverse_lazy
from django.contrib.auth import views as auth_views
from . import views
app_name = 'users'
urlpatterns = [
# include all default auth urls
path('', include('django.contrib.auth.urls')),
path('register/', views.register, name='register'),
path(
'reset_password/',
auth_views.PasswordResetView.as_view(
template_name='registration/password_reset.html',
success_url=reverse_lazy('users:password_reset_done')
) ,
name='reset_password'
),
path(
'reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(
template_name='registration/password_reset_form.html',
success_url=reverse_lazy('users:password_reset_complete')
),
name='password_reset_confirm'
),
path(
'password_reset_done/',
auth_views.PasswordResetDoneView.as_view(
template_name="registration/password_reset_sent.html"),
name='password_reset_done'
),
path(
'password_reset_complete/',
auth_views.PasswordResetCompleteView.as_view(
template_name='registration/password_reset_done.html'),
name='password_reset_complete'
),
path('forgot_username/', views.forgot_username, name="forgot_username"),
path('username_retrieval/', views.username_retrieval, name="username_retrieval"),
]
As you can see, I am using the namespace 'users' in the success_url variable, however, it seems to work on the reset_password path, but it does not seem to work on the reset/<uidb64>/<token> path.
One thing to be aware of is that I have a custom user model in my application. Would that affect my ability to use this default Django password reset method?
In addition, here are my templates under the users/templates/registration/ folder: User App Templates
Some other things to mention:
When I click on the link from my email, I am directed to password_reset_confirm and not password_reset_form so that tells me that the template name is not being overwritten as well.
When I change
success_url=reverse_lazy('users:password_reset_complete')
to
success_url=reverse_lazy('users:password_reset_completed')
the app doesn't look for users:password_reset_completed so that implies that the success_url is not being overwritten.
Any help would be appreciated and I can post more code and answer questions if necessary.
Thanks in advance!
this line is overwriting all your paths:
path('', include('django.contrib.auth.urls')),
just remove it or if you want to keep some of them place it at the end after your paths
Related
I am new to Django. I'm trying to implement jet authentication along with social authentication.
I'm following this tutorial https://jkaylight.medium.com/django-rest-framework-authentication-with-dj-rest-auth-4d5e606cde4d
I tried to implement the same but its not working.
I'm getting this error:
django.urls.exceptions.NoReverseMatch: Reverse for 'account_confirm_email' not found. 'account_confirm_email' is not a valid view function or pattern name.
My project level urls.py
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView
)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
# path('account/', include('allauth.urls')),
path('admin/', admin.site.urls),
path('api/user/', include('user.urls')),
path('api/schema/', SpectacularAPIView.as_view(), name='api-schema'),
path(
'api/docs/',
SpectacularSwaggerView.as_view(url_name='api-schema'),
name='api-docs'
),
]
My App level urls.py
from django.urls import path, re_path
from dj_rest_auth.registration.views import RegisterView, VerifyEmailView, ConfirmEmailView
from dj_rest_auth.views import LoginView, LogoutView
from user import views
app_name = 'user'
urlpatterns = [
path('account-confirm-email/<str:key>/', ConfirmEmailView.as_view()),
path('register/', RegisterView.as_view()),
path('login/', LoginView.as_view()),
path('logout/', LogoutView.as_view()),
path('verify-email/',
VerifyEmailView.as_view(), name='rest_verify_email'),
path('account-confirm-email/',
VerifyEmailView.as_view(), name='account_email_verification_sent'),
re_path(r'^account-confirm-email/(?P<key>[-:\w]+)/$',
VerifyEmailView.as_view(), name='account_confirm_email'),
path('listusers/', views.ListUsers.as_view(), name='list-users'),
]
When I try to register a user. It causes this error.
I'm using dj-rest-auth package to implement authentication.
If I replace the email verification related urls from app level to project level. Then everything is working fine.
What is causing this error ?
For the registration part, you have to use allauth which has some baked-in integrations with dj-rest-auth
also, you would have to add some things in your settings.py:
INSTALLED_APPS = [
"dj_rest_auth.registration",
"allauth",
"allauth.account"
]
AUTHENTICATION_BACKENDS = [
"allauth.account.auth_backends.AuthenticationBackend",
"django.contrib.auth.backends.ModelBackend",
]
add these URLs to the urls.py:
urlpatterns = [
path("signup/", include("dj_rest_auth.registration.urls"))
path("verify-email/", VerifyEmailView.as_view(), name="rest_verify_email"),
path(
"account-confirm-email/",
VerifyEmailView.as_view(),
name="account_confirm_email_sent",
),
path(
"account-confirm-email/<key>/",
VerifyEmailView.as_view(),
name="account_confirm_email",
),
]
The request is not getting <str:key>. Please check where you are supplying. It can be from view or template.
My main application is called lpbsmain, and I have another app called dashboard.
lpbsmain/urls.py includes path('main/', include('dashboard.urls')) in the urlpatterns variable.
dashboard/urls.py looks like...
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
#path('', views.dashboard, name='dashboard'),
path('<str:useremail>/', views.dashboard, name='main'),
path('base_dash/', views.base_dashboard, name='baseDash')
]
dashboard/views.py has two view functions, dashboard() and base_dashboard()
import requests, json
from django.shortcuts import render, redirect, HttpResponse
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
def base_dashboard(request):
print("base dashboard view func print statement")
return render(request, "base-main-dashboard.html")
#login_required(login_url='/login')
def dashboard(request, useremail):
if request.user.is_authenticated:
# removed code in this conditional because it's not relevant
return render(request, "index.html", {'Past30Dates':json.dumps(past_30_dates), 'Past30Values':json.dumps(past_30_values), 'Past60Dates':json.dumps(past_60_dates), 'Past60Values':json.dumps(past_60_values), 'fullEmail':useremail, 'shortenedEmail':shortenedEmail})
else:
redirect("login")
The problem: So if you try to go to the url /main/base_dash, my intent is to see base-main-dashboard.html. Instead, I actually see index.html. From adding print statements, I see that whenever I go to the url /main/base_dash/, the view function dashboard(useremail) is actually being executed, not base_dashboard(). Normally, dashboard(useremail) gets executed from the url main/<useremail> as expected. But now it's also executing at that url and main/base_dash.
The only way this stops is if I remove path('<str:useremail>/', views.dashboard, name='main'), from dashboard/urls.py. Then, if I go to main/base_dash then only base_dashboard() gets executed.
If these view functions are mapped to two different urls, I don't get why going to one url is triggering the other. So are they mapped correctly or did I do something wrong?
Why would the existence of one url affect the other in this case?
I'm running django locally on a development server.
The order of urls, when django scans the url patterns it gives more importance to the 1st one
https://docs.djangoproject.com/en/3.1/topics/http/urls/#how-django-processes-a-request
-> In this case any url ( /main/base_dash ) will be matched against < str:useremail > and it checks out ( base_dash can be parsed as string )
Either refactor the url pattern ( which i recommend to be more good approach )
urlpatterns = [
#path('', views.dashboard, name='dashboard'),
path('base_dash/', views.base_dashboard, name='baseDash'),
path('email/<str:useremail>/', views.dashboard, name='main'),
]
or just try changing the order as follows.
urlpatterns = [
#path('', views.dashboard, name='dashboard'),
path('base_dash/', views.base_dashboard, name='baseDash'),
path('<str:useremail>/', views.dashboard, name='main'),
]
The problem is that you make a call to the link via the include and then add the extension again, and this does not work
try this
path('', include('dashboard.urls'))
res:
enter link description here
I have been building a user account functionality for a Django app. In doing so, I have come across a problem and am uncertain of whether I am doing something wrong or have encountered an unfamiliar quirk of Django/Python. Any help is appreciated.
I have the following set of (working) urls (user_accounts/urls.py):
app_name = 'user_accounts'
urlpatterns = [
path('signup', views.UserSignUpView.as_view(), name='signup'),
path('logout', auth_views.LogoutView.as_view(), name='logout'),
path('login', auth_views.LoginView.as_view(template_name='user_accounts/login.html'), name='login'),
re_path(r'^reset/$', auth_views.PasswordResetView.as_view(template_name='user_accounts/password_reset.html', email_template_name='user_accounts/password_reset_email.html', subject_template_name='user_accounts/password_reset_subject.txt'), name='password_reset'),
re_path(r'^reset/done/$', auth_views.PasswordResetDoneView.as_view(template_name='user_accounts/password_reset_done.html'), name='password_reset_done'),
re_path(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', auth_views.PasswordResetConfirmView.as_view(template_name='user_accounts/password_reset_confirm.html'), name='password_reset_confirm'),
re_path(r'^reset/complete/$', auth_views.PasswordResetCompleteView.as_view(template_name='user_accounts/password_reset_complete.html'), name='password_reset_complete')
]
I have been trying to test it as follows (user_accounts/tests/test_views_forms.py):
class SuccessfulPasswordResetTests(TestCase):
def setUp(self):
email = 'jon#doe.com'
User.objects.create_user(username='john', email=email, password='123abcdef')
url = reverse('user_accounts:password_reset')
print(reverse('user_accounts:password_reset_done'))
self.response = self.client.post(url, {'email': email})
def test_redirection(self):
'''
A valid form submission should redirect to password_reset_done
'''
url = reverse('password_reset_done')
self.assertRedirects(self.response, url)
The issue is that I get the following error:
File
"/home/user-name/sites/project-web/project/user_accounts/tests/test_views_forms.py",
line 128, in setUp
self.response = self.client.post(url, {'email': email})
django.urls.exceptions.NoReverseMatch: Reverse for
'password_reset_done' not found. 'password_reset_done' is not a valid
view function or pattern name.
Yet, when I navigate directly to /user/reset/done/ in the browser, it serves the proper template.
The project's urls.py file looks as follows. Please note that I am using DjangoCMS
from django.contrib import admin
from django.urls import include, path
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('video/', include('video_uploader.urls')),
path('user/', include('user_accounts.urls')),
path('', include('cms.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
You just need to set the success_url attribute in the PasswordResetView. Out of the box it defaults to reverse_lazy('password_reset_done') but since you're using a custom app name the url can't be resolved even though the namespace is the same.
This should do the trick:
re_path(r'^reset/$', auth_views.PasswordResetView.as_view(
template_name='user_accounts/password_reset.html',
success_url=reverse_lazy('user_accounts:password_reset_done'),
email_template_name='user_accounts/password_reset_email.html',
subject_template_name='user_accounts/password_reset_subject.txt'), name='password_reset')
This is a working code. Note the addition of success_url in several paths, which end up working as a cascade. That is one gets triggered after another. I also converted from the regex format to the path format. This may have been needed to get the thing working as well.
from django.urls import path, re_path, reverse_lazy, include
from django.contrib.auth import views as auth_views
from . import views
app_name = 'user_accounts'
urlpatterns = [
path('signup/', views.UserSignUpView.as_view(), name='signup'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('login/', auth_views.LoginView.as_view(template_name='user_accounts/login.html'), name='login'),
path('password-change/', auth_views.PasswordResetView.as_view(template_name='user_accounts/password_reset.html', email_template_name='user_accounts/password_reset_email.html', subject_template_name='user_accounts/password_reset_subject.txt', success_url = reverse_lazy('user_accounts:password_reset_done')), name='password_reset'),
path('password-change/done/', auth_views.PasswordResetDoneView.as_view(template_name='user_accounts/password_reset_done.html'), name='password_reset_done'),
#re_path(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', auth_views.PasswordResetConfirmView.as_view(template_name='user_accounts/password_reset_confirm.html'), name='password_reset_confirm'),
path('password-change/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name='user_accounts/password_reset_confirm.html', success_url = reverse_lazy('user_accounts:password_reset_complete')), name='password_reset_confirm'),
path('password-change/complete/', auth_views.PasswordResetCompleteView.as_view(template_name='user_accounts/password_reset_complete.html'), name='password_reset_complete')
]
i am a beginner to Django and i am unable to properly handle redirects from one app to another. I have 2 apps Accounts, Dashboard. Accounts Handles login and registration of AuthUser. Dashboard handles other functionality like Fileupload
So far, I have successfully using reverse() method have redirected from /accounts/login to my upload page but it redirects from /accounts/login to /accounts/upload instead of /dashboard/upload .
Project URLS
urlpatterns = [
path('dashboard/', include('Dashboard.urls')),
path('accounts/', include('Accounts.urls')),
path('admin/', admin.site.urls),
]
Account urls.py
urlpatterns = [
url('upload',DashboardViews.upload, name='upload'),
path('login', views.login, name='Login'),
path('register', views.register, name='Register'),
path('logout', views.logout, name='logout')
]
Account views.py
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
if request.method == 'POST':
user_name = request.POST.get("username")
password = request.POST.get("password")
user = auth.authenticate(username=user_name,password=password)
if user is not None:
auth.login(request,user)
return redirect(reverse('upload'))
else:
print('Failed')
return render(request,'login')
My intention is whenever user (login/register), web page should redirect from /account/login to /dashboard/upload.
This is because you have the upload url defined in the urlpatterns of your Accounts app.
You should place it in the urls.py file from the Dashboard app if you want the full path to be /dashboard/upload, instead of /accounts/upload.
To explain it a bit more, when you define a path with the include function, like this:
path("accounts/", include("Accounts.urls")
All the urls from the Accounts app will have "accounts/" appended at the beginning.
Note: If you add the name parameter to a path, you can use it in all your apps with the reverse function. The path doesn't have to be declared in the same app where you want to call the reverse function.
A good practice to avoid having url conflicts is to add the name of the app to the url. So you should maybe name the upload path as dashboard_upload.
I faced the same problem, but below technique worked for me.
In your urls.py file of Dashboard app, use app_name = "Dashboard". then in your redirect() function use appName:Path structure. For example, use redirect('Dashboard:upload')
I am using Django 2.1 and getting an error during password reset authentication right at the end.
my urls
from django.conf.urls import url
from django.contrib import admin
from . import views
from django.contrib.auth import views as auth_views
from django.urls import reverse, reverse_lazy, resolve
app_name = 'partners'
urlpatterns = [
url(r'^$', views.home, name='partner_home'),
url(r'^(?P<partner_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^login/$',auth_views.LoginView.as_view(template_name="partners/registration/login.html"), name="login"),
url(r'^logout/$',auth_views.LogoutView.as_view(template_name="partners/registration/logout.html"), name="logout"),
url(r'^register/$', views.register, name='register'),
url(r'^profile/$', views.view_profile, name='view_profile'),
url(r'^profile/edit/$', views.edit_profile, name='edit_profile'),
# Password URL's ###################################################################################################
url(r'^change-password/$', views.change_password, name='change_password'),
url(
r'^password_reset/$',
auth_views.PasswordResetView.as_view(
template_name="partners/registration/password_reset.html",
email_template_name="partners/registration/password_reset_email.html",
success_url=reverse_lazy("partners:password_reset_done"), # might be required
),
name='password_reset'
),
url(r'^password_reset_done/',
auth_views.PasswordResetDoneView.as_view(
template_name="registration/password_reset_done.html",
),
name='password_reset_done'
),
url(r'^password_reset_confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
# r'(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
auth_views.PasswordResetConfirmView.as_view(
template_name="registration/password_reset_confirm.html",
),
name='password_reset_confirm',
),
url(r'^password_reset_complete/$',
auth_views.PasswordResetCompleteView.as_view(
template_name="partners/registration/password_reset_complete.html",
),
name="password_reset_complete"
),
]
I am able to login, then go to the password reset view. An email is sent using the development server and I am able to use the link to create a new password. Once I enter the new password I get an error (but the password in the background is changed). I am not sure why this is the case at the moment .
I am not using my custom password_reset_xxx html file instead I am using the builtin views
My URLS and structure
The Error Message
You have put your password reset urls in the partners app, therefore you need to override the code wherever it reverses urls so that it uses the partners namespace.
In this case, you need to override success_url in PasswordResetConfirmView.
auth_views.PasswordResetConfirmView.as_view(
template_name="registration/password_reset_confirm.html",
success_url = reverse_lazy('partners:password_reset_complete')
),
However, you may find there are other places that you need to override to get the password reset working. As I suggested on your other question, it would be simpler to move the password reset URLs out of the partners app.