using django authentication password_reset_confirm error - django

I have an error with password reset. If I attempt to reset using an invalid email I get the password reset sent notice. If I use a valid email I get NoReverseMatch error message
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
# Password URL's ###################################################################################################
url(r'^change-password/$', views.change_password, name='change_password'),
url(
r'^password_reset/$',
auth_views.PasswordResetView.as_view(
template_name="registration/password_reset.html",
email_template_name="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(
),
name='password_reset_done'
),
url(r'^password_reset_confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
auth_views.PasswordResetConfirmView.as_view(
template_name="registration/password_reset_confirm.html",
success_url=reverse_lazy("partners:password_reset_complete"), # might be required
),
name='password_reset_confirm'
),
url(r'^password_reset_complete/$',auth_views.PasswordResetCompleteView.as_view(), name="password_reset_complete"),
]
Please see my screen grabs for my project structure and the error message
project structure
error message received
{% block head %}
<meta charset="UTF-8">
<title>Welcome ! You can login here !</title>
{% endblock head %}
{% block body %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-3">
<h3>Password Reset Email</h3>
<p>Provide your registered email address </p>
{% autoescape off %}
To initiate the password reset process for your {{ user.get_username }} TestSite Account,
click the link below:
{{ protocol }}://{{ domain }}{% url 'partners:password_reset_confirm' uidb64=uid token=token %}
If clicking the link above doesn't work, please copy and paste the URL in a new browser
window instead.
Sincerely,
The AV's BlogTeam
{% endautoescape %}
</div>
</div>
</div>
{% endblock content %}
{% endblock body %}
I am building this in a "partners app" where I have templates/registration with the above password_reset_confirm.html
Password reset email is as below
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'partners:password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}
PLEASE HELP

If you want Django to use the template from your partners app, you need to move partners above django.contrib.admin in your INSTALLED_APPS setting.
I would suggest that you move the password reset urls into a urls.py that does not use the partners namespace. Using {% url 'partners:password_reset_confirm' ... %} will fix this specific error, but there are several other places that you will have to make changes to use the namespace, and I don't think it's worth the effort.

Related

how to customize sent emails in djoser?

I build React&Django project and use Djoser for registration and auth. I want to customize sent email content on Gmail. Where should I change it?
In your django directory create an app or in existing app <my_app>
create a file
email.py
then in <my_app> directory create template folder like:
templates/<my_app>/
within the directory <my_app> create two html files:
ActivateEmail.html
ConfirmationEmail.html
Then in ActivationEmail.html add this code below:
{% load i18n %}
{% block subject %}
{% blocktrans %}Account activation on {{ site_name }}{% endblocktrans %}
{% endblock subject %}
{% block text_body %}
{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page to activate account:" %}
{{ protocol }}://{{ domain }}/{{ url|safe }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}</p>
<p>{% trans "Please go to the following page to activate account:" %}</p>
<p>{{ protocol }}://{{ domain }}/{{ url|safe }}</p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}
And in your ConfirmationEmail.html add this code:
{% load i18n %}
{% block subject %}
{% blocktrans %}{{ site_name }} - Your account has been successfully created and activated!{% endblocktrans %}
{% endblock %}
{% block text_body %}
{% trans "Your account has been created and is ready to use!" %}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% trans "Your account has been created and is ready to use!" %}</p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}
Then email.py within your app <my_app> add this code below:
from djoser import email
from djoser import utils
from djoser.conf import settings
from django.contrib.auth.tokens import default_token_generator
class ActivationEmail(email.ActivationEmail):
template_name = '<my_app>/ActivationEmail.html'
def get_context_data(self):
# ActivationEmail can be deleted
context = super().get_context_data()
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
return context
class ConfirmationEmail(email.ConfirmationEmail):
template_name = '<my_app>/ConfirmationEmail.html'
then EDIT
ActivationEmail.html
ConfirmationEmail.html
however you LIKE.
Then the last step is to add The classes in email.py to replace the default templates
in activation/confirmation email.
The defaults are as in docs: djoser docs
Then in Djoser settings in settings.py file:
DJOSER = {
'USER_CREATE_PASSWORD_RETYPE': True,
'SEND_CONFIRMATION_EMAIL': True,
'SEND_ACTIVATION_EMAIL': True,
'ACTIVATION_URL': 'activate/{uid}/{token}',
'HIDE_USERS': True,
'SERIALIZERS': {
'user': 'myapp.serializers.UserCreateSerializer',
'user_create': 'myapp.serializers.UserCreateSerializer',
'current_user': 'myapp.serializers.UserSerializer',
},
(...)
}
Add this:
DJOSER = {
'USER_CREATE_PASSWORD_RETYPE': True,
'SEND_CONFIRMATION_EMAIL': True,
'SEND_ACTIVATION_EMAIL': True,
'ACTIVATION_URL': 'activate/{uid}/{token}',
'HIDE_USERS': True,
'SERIALIZERS': {
'user': 'myapp.serializers.UserCreateSerializer',
'user_create': 'myapp.serializers.UserCreateSerializer',
'current_user': 'myapp.serializers.UserSerializer',
},
'EMAIL': {
'activation': 'myapp.email.ActivationEmail',
'confirmation': 'myapp.email.ConfirmationEmail',
},
(...)
}
Then send Email activation instead of sending default template for user in his/her email, it'll send the ActivationEmail.html template for them
Note that the Djoser uses the django-template-mail for its activation email template.

Django 3: Badly formed URL in password_reset_email.html

I have a Django 3.0.7 app using the default template for sending password reset emails.
For some of our users, the link to reset is badly formed, e.g.:
https://foo.bar/accounts/reset/McU4Mw/5no-9cd52590f0943503=
fa3a/
/>
While it should be:
https://foo.bar/accounts/reset/McU4Mw/5no-9cd52590f0943503fa3a/
This second one is whats actually being sent. But, as I said, some users are receiving the first one.
I assume some of my users' email clients are wrecking the text, but what could I do?
I've considered adding a plaintext url to the email, but it's already plaintext.
EDIT: This is a solution I came up with, and it works. Can anyone think of a reason not to do this?
urls.py
...
path('accounts/reset/<uidb64>/<token>/<str:extra_chars>/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('accounts/reset/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
...
EDIT:
Here's the default template:
/site-packages/django/contrib/admin/templates/registration/password_reset_email.html
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans 'Your username, in case you’ve forgotten:' %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}

Logout link not working django

In urls.py I have the following
from django.conf.urls import url
from django.contrib.auth.views import logout
from core import views as core_views
urlpatterns = [
url(r'^logout/$', logout, {'template_name': 'core/logout.html'}, name='logout'),
url(r'^profile/$', core_views.view_profile, name = 'view_profile'),
etc...
]
I have a base.html that is included on every page:
<!doctype html>
<head>
{% block head %}
<title>base</title>
{% endblock %}
</head>
<body>
<a href = 'core/logout.html'>Logout</a>
{% block body %}
{% endblock %}
</body>
</html>
The profile.html page:
{% extends 'core/base.html' %}
{% block head %}
<title> Profile</title>
{% endblock %}
{% block body %}
<h2>Profile</h2>
<p>
{{ user.first_name }}<br/>
{{ user.last_name }}<br/>
{{ user.email }}<br/>
{{ user.userprofile.city }}
</p>
{% endblock %}
The logout.html page:
{% extends 'core/base.html' %}
{% block head %}
<title>Logout</title>
{% endblock %}
{% block body %}
<p>Logged out</p>
{% endblock %}
The problem is if the user is at /profile and clicks the logout link at the top of the page it sends the user to /profile/logout which does not exist, how do I get it to send the user to /logout ?
Instead using:
<a href = 'core/logout.html'>Logout</a>
you should use
Logout

NoReverseMatch at /user_details/reset-password

I know it's well asked, but somehow none of the other answers seemed to solve my problem.
I get an error with the ReverseMatch, here is the relevant urls.py section:
# for password reset
url(r'^reset-password$','django.contrib.auth.views.password_reset', {'post_reset_redirect' : 'user_details/reset_password.html', 'template_name': 'user_details/reset_password.html'}, name="password_reset"),
url(r'^reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'post_reset_redirect' : 'user_details/reset_password.html'}, name="password_reset_confirm"),
I think the name is adequately defined?
The problem is in the template /usr/lib/python2.7/dist-packages/django/contrib/admin/templates/registration/password_reset_email.html, error at line 6:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
where the {% url ...} is highlighted in red.
Why?
I assume that Django would then use the default template for that view?
Thanks!
Chris
Right, I had to resolve to overwriting the Django default email, because the reverse URL lookup doesn't want to behave properly.
So I created a copy of the original Django email file (/usr/lib/python2.7/dist-packages/django/contrib/admin/templates/registration/password_reset_email.html):
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}
and replaced line 6 with the following:
{{ protocol }}://{{ domain }}/user_details/reset/{{uid}}/{{token}}
which matches my urls.py.
This does indeed work now...
You have defined a URL which accepts a "uidb36" parameter, but the reverse call is passing "uidb64".

Resetting Password in Django

I have problem in resetting password in Django . After looking at this:Resetting Password, this error still exist....
My error is:
Reverse for 'django.contrib.auth.views.password_reset_confirm' with arguments '()' and keyword arguments '{'uidb36': '1', 'token': '392-804fab6dcec790f0ec6b'}' not found.
Here is my urls.py:
urlpatterns = patterns('lex.views',
url(r'^home/forgotpassword', 'lexrequestpassword', name='lexrequestpassword'),
url(r'^home/resetpassword', 'lexresetpassworddone', name='lexresetpassworddone'),
url(r'^home/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'lexresetpasswordconfirmed', name='lexresetpasswordconfirmed'),
url(r'^home/resetpasswordcompleted', 'lexresetpasswordcompleted', name='lexresetpasswordcompleted'),)
My views.py:
#login_required
def lexrequestpassword(request):
"""
Reset Password
"""
path = reverse('lexresetpassworddone')
return password_reset(request,post_reset_redirect=path)
#login_required
def lexresetpassworddone(request):
"""
Reset Password Done
"""
path = reverse('lexresetpasswordconfirmed')
return password_reset_done(request,template_name=path)
#login_required
def lexresetpasswordconfirmed(request):
"""
Reset Password Confirmed
"""
path = reverse('lexresetpasswordcompleted')
return password_reset_confirm(request,post_reset_redirect=path)
#login_required
def lexresetpasswordcompleted(request):
"""
Reset Password Completed
"""
path = reverse('lexmain')
return password_reset_complete(request,post_reset_redirect=path)
Not sure how to solve this. Need some guidance...
Password Reset
Django has a built-in password reset functions which we are going to use. In this tutorial we will name our app as accounts.
urls.py
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
admin.autodiscover()
urlpatterns = patterns('',
url(
r'^admin/',
include(admin.site.urls)
),
#this is the url for password reset authentication
#Don't remove, this is important!
url(
r'^account/',
include('django.contrib.auth.urls')
),
#this is the accounts app main url
url(
r'^accounts/',
include('accounts.urls', namespace="accounts")
),
)+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += staticfiles_urlpatterns()
urls.py
from django.conf.urls import *
urlpatterns = patterns('accounts.views',
url(
r'^forgot-password/$',
'forgot_password',
name="forgot-password"
),
)
views.py
from django.contrib.auth.views import password_reset
from django.shortcuts import render
def forgot_password(request):
if request.method == 'POST':
return password_reset(request,
from_email=request.POST.get('email'))
else:
return render(request, 'forgot_password.html')
Put your base.html in your main templates folder
base.html
<html>
<head>
<title>{% block title %}{% endblock title %}</title>
</head>
<body>
{% block content %}{% endblock content %}
</body>
</html>
put this template in the app templates folder.
forgot_password.html
{% extends "base.html" %}
{% block title %}Forgot Password{% endblock title %}
{% block content %}
<form method="post" action="{% url django.contrib.auth.views.password_reset %}">
{% csrf_token %}
<p>Please enter your email address.
You will receive a link to create a new password via email.</p>
<input type="email" name="email"
placeholder="Your e-mail"><br/>
<button type="submit">Send new password</button>
</form>
{% endblock content %}
settings.py
#add email settings
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'user'
EMAIL_HOST_PASSWORD = 'password'
DEFAULT_FROM_EMAIL = 'your email'
Now we will override the password reset templates of the admin. In your main templates folder create registration folder. Inside the registration folder, create these files:
If you want to change the contents of the files. Make sure it is correct or else you will got an errors.
password_reset_complete.html
{% extends "base.html" %}
{% block title %}Password reset complete{% endblock title %}
{% block content %}
<h4>Reset Complete</h4>
<p>Your password has been set.
You may go ahead and log in now.</p>
Log in
{% endblock content %}
password_reset_confirm.html
{% extends "base.html" %}
{% block title %}Setting New password{% endblock title %}
{% block content %}
<h4>Set New Password</h4>
<form action="" method="post">
{% csrf_token %}
{% if validlink %}
<p>Please enter your new password twice.
So we can verify you typed it in correctly.</p>
<p>
{{ form.new_password1.errors }}<br/>
{{ form.new_password1 }}
</p>
<p class="button-height">
{{ form.new_password2.errors }}<br/>
{{ form.new_password2 }}
</p>
{% else %}
<h4>Password reset unsuccessful</h4>
<p>The password reset link was invalid,
possibly because it has already been used.
Please request a new password reset.</p><br/>
{% endif %}
<button type="submit">Change my password</button>
</form>
{% endblock content %}
password_reset_done.html
{% extends "base.html" %}
{% block title %}Password reset successful{% endblock title %}
{% block content %}
<h4>Reset Password</h4>
<p>We've e-mailed you instructions for setting
your password to the e-mail address you submitted.</p>
<p>You should be receiving it shortly.</p>
<p>Login</p>
{% endblock content %}
#password_reset_ email.html
{% load i18n %}
{% load url from future %}
{% autoescape off %}
{% blocktrans %}
You're receiving this e-mail because you requested
a password reset for your user account at {{ site_name }}.
{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb36=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}
password_reset_form.html
{% extends "base.html" %}
{% block title %}Password reset form{% endblock title %}
{% block content %}
<h4>Reset Password</h4>
<p>Forgotten your password?
Enter your e-mail address below,
and we'll e-mail instructions for setting a new one.</p>
<form action="" method="post">
{% csrf_token %}
{% if form.email.errors %}`enter code here`
<div class="message red-gradient">{{ form.email.errors }}</div><br/>
{% endif %}
<p>E-mail address: {{ form.email }} <br/><br/>
<input type="submit" value="Reset my password"></p>
</form>
{% endblock content %}
Than your def lexresetpasswordconfirmed(request): should accept also uidb36 and token args.
Reverse for 'django.contrib.auth.views.password_reset_confirm' with arguments '()' and keyword arguments '{'uidb36': '1', 'token': '392-804fab6dcec790f0ec6b'}' not found.
This means that at some point in the execution, you are not calling reverse on lexresetpasswordconfirmed, you are calling it on django.contrib.auth.views.password_reset_confirm.
Where is this error occurring? In the template? If so, make sure that the template you are using has
{% url lexresetpasswordconfirmed uid token %}
and not
{% url django.contrib.auth.views.password_reset_confirm uid token %}
Is the error occurring in a view? If so, somewhere you are calling reverse on django.contrib.auth.views.password_reset_confirm.
Once that error is resolved, then yes you will have to resolve the other error that Alexander pointed out, namely including the uuid and token in the view function:
#login_required
def lexresetpasswordconfirmed(request, uuid36, token):
"""
Reset Password Confirmed
"""
# you need to do SOMETHING with the uuid and token here, RIGHT?!?!
path = reverse('lexresetpasswordcompleted')
return password_reset_confirm(request,post_reset_redirect=path)
So I'm guessing on each of these returns you're using the views from django.contrib.auth, correct? Problem is that one of these views -- probably password_reset_done -- doesn't care that you've provided it with a redirect, it's using its own.
My settings.py:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASS')
My urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', user_views.register,name='register'),
path('profile/', user_views.profile,name='profile'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'),name='login'),
path('logout/',auth_views.LogoutView.as_view(template_name='users/logout.html'),name='logout'),
path('password-reset/',auth_views.PasswordResetView.as_view(template_name='users/password_reset.html'),name='password_reset'),
path('password-reset/done/',auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'),name='password_reset_done'),
path('password-reset-confirm/<uidb64>/<token>/',auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),name='password_reset_confirm'),
path('password-reset-complete/',
auth_views.PasswordResetCompleteView.as_view(
template_name='users/password_reset_complete.html'
),
name='password_reset_complete'),
path('', include('blog.urls')),
]
password_reset.html:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Reset Password</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Request Password Reset</button>
</div>
</form>
</div>
{% endblock content %}
password_reset_done:
{% extends "blog/base.html" %}
{% block content %}
<div class="alert alert-info">
An email has been sent with instructions to reset your password
</div>
{% endblock content %}
password_reset_confirm.html:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Reset Password</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Reset Password</button>
</div>
</form>
</div>
{% endblock content %}
password_reset_complete.html:
{% extends "blog/base.html" %}
{% block content %}
<div class="alert alert-info">
Your password has been set.
</div>
Sign In Here
{% endblock content %}