I'm fairly new to django and I'm currently rewriting the django login views so I can move all the authentication process to a dedicated django app where I can redefine the templates.
So currently I have an accounts app which url.py looks like that:
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
app_name = 'accounts'
urlpatterns = [
path('login/', auth_views.login, {'template_name': 'accounts/login.html'}, name='login'),
path('logout/', auth_views.logout, name='logout'),
path('password_reset/', auth_views.password_reset,
{'template_name': 'accounts/password_reset_form.html',
'email_template_name': 'accounts/password_reset_email.html',
'subject_template_name': 'accounts/password_reset_subject.txt',
'post_reset_redirect': 'done/'}, name='password_reset'),
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(
template_name='accounts/password_reset_done.html'), name='password_reset_done'),
path('reset/<uidb64>/<token>/', auth_views.password_reset_confirm,
{'template_name': 'accounts/password_reset_confirm.html',
'post_reset_redirect': '/accounts/reset/done/'}, name='password_reset_confirm'),
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(
template_name='accounts/password_reset_complete.html'), name='password_reset_complete')
]
And a accounts/password_reset_email.html which looks like this:
{% autoescape off %}
To initiate the password reset process for your {{ user.get_username }} account,
click the link below:
{{ protocol }}://{{ domain }}{% url 'accounts:password_reset_confirm' uidb64=uid token=token %}?origin_page={{ request.POST.origin_page }}"
...
Sincerely,
The Team
{% endautoescape %}
What I want to do is to recover the origin_page argument so when the user click on the reset link from the email he get redirected to the right webpage after his password is reset. So far I tried to do this in password_reset_form.html:
{% block content %}
<p>Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one.</p>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="origin_page" value="{{ request.GET.origin_page }}"/>
<button type="submit">Submit</button>
</form>
{% endblock %}
Here I just want to pass in my origin_page to the submit form so that I can retrieve it from accounts/password_reset_email.html, the url for this page looks like this http://127.0.0.1:8000/accounts/password_reset/?origin_page=/mypage/.
How can I recover the request.POST.origin_page parameter from accounts/password_reset_email.html?
Thanks.
maybe that helps
path('password-reset/',
auth_views.PasswordResetView.as_view(
template_name='form.html',
email_template_name='email.html',
extra_email_context={
'origin_page':'origin_page_thing'
}
),
name='password_reset'),
email:
{{ protocol }}://{{ domain }}{% url 'accounts:password_reset_confirm' uidb64=uid token=token %}?origin_page={{ origin_page }}
E-Kami solution:
Ok I've got it, I actually created a new PasswordResetView like this: ' \
class PasswordResetView(auth_views.PasswordResetView):
template_name = 'commons/password_reset_form.html'
email_template_name = 'commons/password_reset_email.html'
subject_template_name = 'commons/password_reset_subject.txt'
success_url = 'done/'
def post(self, request, *args, **kwargs):
self.extra_email_context = {
'origin_page': self.request.POST['origin_page']
}
return super().post(request, *args, **kwargs)
Related
In my Django Rest Framework, the users request to reset the password and when the email is received and the link is clicked, the url
password-reset-confirm/<uidb64>/<token>/ as comes up requested but the form is not showing and when I added it as {{ form }} is displayed NONE
The password reset process is working perfectly fine when I do everytihng on the Django but if I try to reset the password from Django
Rest Framework the form does not appear.
Here is the main urls.py
urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('password-reset/', auth_views.PasswordResetView.as_view(template_name='users/password_reset.html', success_url=reverse_lazy('password_reset_done')), 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('admin/', admin.site.urls),
path('api/', include('api.urls'), ),
path('users/', include('users.urls'), ),
]
Here is the API app urls.py that is related to DRF
app_name = 'api'
router = routers.DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = [
path('', include(router.urls)),
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
here is the template password_reset_confirm.html
<main class="mt-5" >
<div class="container dark-grey-text mt-5">
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Reset Password</legend>
{{ form|crispy }}
{{ form }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Reset Password</button>
</div>
</form>
</div>
</div>
</main>
My question is: Why is the form showing as NONE and how do I fix it.
Most probably the form is not going to password_reset_confirm.html since django-rest-framework does not include the form in the context of the PasswordResetConfirmView by default.
Currently, the thing you can do is to create a custom PasswordResetConfirmView by inheriting it in a sub class and pass the form to the template context, using form_class attribute so:
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.views import PasswordResetConfirmView
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
class CustomPasswordResetConfirmView(PasswordResetConfirmView):
form_class = SetPasswordForm
success_url = reverse_lazy('password_reset_complete')
template_name = 'users/password_reset_confirm.html'
#method_decorator(sensitive_post_parameters('new_password1', 'new_password2'))
#method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form_class(user=self.request.user)
return context
Then in urls.py:
urlpatterns = [
# .......
path('password-reset-confirm/<uidb64>/<token>/', CustomPasswordResetConfirmView.as_view(), name='password_reset_confirm'),
# .......
]
You can provide any success_url according to your need.
I am using the PasswordResetView of django.contrib.auth.views. I am trying to direct my path('reset-password/'...) to use my 'rest_password_email.html' template after the user has submitted an email address for password reset. I have added this as a kwargs, however django is not recognizing it and continues to direct the application to default 'password_reset_email.html'. Any suggestions on how this can be achieved? thanks.
BTW: I am using namespace 'accounts'. Hence the reason for doing the above is to introduce the amended url in my template to account for the namespace.
url.py
from django.urls import path
from . import views
from django.contrib.auth.urls import urlpatterns
from django.contrib.auth.views import (
LoginView, LogoutView,
PasswordResetView, PasswordResetDoneView,
PasswordResetConfirmView,
PasswordResetCompleteView
)
from django.urls import reverse_lazy
app_name = 'accounts'
urlpatterns = [
path('', views.home, name = 'home'),
path('column/', views.column),
path('login/', LoginView.as_view(template_name='accounts/login.html'), name = 'login'),
path('logout/', LogoutView.as_view(template_name='accounts/logout.html'), name = 'logout'),
path('register/', views.register, name = 'register'),
path('profile/', views.view_profile, name = 'view_profile'),
path('profile/edit/', views.edit_profile, name = 'edit_profile'),
path('change_password/', views.change_password, name = 'change_password'),
path('reset-password/', PasswordResetView.as_view(template_name='accounts/reset_password.html'), kwargs={'email_template_name':'accounts/reset_password_email.html','post_reset_redirect': reverse_lazy('accounts:password_reset_done')}, name = 'password_reset'),
path('reset-password/done', PasswordResetDoneView.as_view(), name = 'password_reset_done'),
path('reset-password/confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', PasswordResetConfirmView.as_view(), name = 'password_reset_confirm'),
path('reset-password/complete/$', PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]
reset_password_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 'accounts: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 %}
You can set your email_template_name in PasswordResetView,
url(r'^reset-password/$',
PasswordResetView.as_view(template_name='accounts/reset_password.html'),
{
'email_template_name': 'accounts/reset_password_email.html',
'success_url' : reverse_lazy('accounts:reset_password_done')
},
name='reset_password'),
or you can directly pass it in .as_view()
url(r'^reset-password/$',
PasswordResetView.as_view(template_name='accounts/reset_password.html',
email_template_name = 'accounts/reset_password_email.html',
success_url = reverse_lazy('accounts:reset_password_done')) ,
name='reset_password'),
The connection error issue is resolved and the reset password is working now. I was missing an Email backend in settings.py. Included: EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
I have found many similar questions to this issue. This question was one of them, but it didn't solve my problem, so I will ask my own question.
I'm making a password reset page on my website. But when I go to http://localhost:8000/users/reset-password and enter my email and clicks on 'Reset my password', then Django throws a NoReverseMatch error at me.
The error is:
NoReverseMatch at /users/reset-password/
Reverse for 'password_reset_confirm' not found. 'password_reset_confirm' is not a valid view function or pattern name.
I believe there's something wrong with how I write my urlpatterns.
I've tried:
Making my own views and templates.
Rewriting all my urlpatterns.
My Code
urls.py:
"""Defines URL Patterns for users."""
from django.urls import re_path
from django.contrib.auth.views import (
LoginView, PasswordResetView, PasswordResetConfirmView,
PasswordResetDoneView,
)
from . import views
urlpatterns = [
# Login Page.
re_path(r'^login/$', LoginView.as_view(template_name='users/login.html'),
name='login'),
# Logout Page.
re_path(r'^logout/$', views.logout_view, name='logout'),
# Registration Page.
re_path(r'^register/$', views.register, name='register'),
# Password reset Page.
re_path(r'^password_reset/$', PasswordResetView.as_view(
# This is the only line I added in this file.
template_name='users/password_reset_email.html'
),
name='password_reset'),
# Password reset done Page.
re_path(r'^password_reset/done/$', PasswordResetDoneView.as_view(),
name='password_reset_done'),
# Password reset confirm Page.
re_path(r'^password_reset/confirm/'
+ '(?P<uidb64>[0-9A-Za-z]+)/(?P<token>.+)/$',
PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
]
My own users/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 'users: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 %}
Update:
I got something right. Now I get a NoReverseMatch at /users/password_reset/
Reverse for 'password_reset_confirm' with keyword arguments '{'uidb64': '', 'token': ''}' not found. 1 pattern(s) tried: ['users/password_reset/confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$']. I got to this error by using my own template of djangos password_reset_email.html, where I modified the line: {% url 'password_reset_confirm' uidb64=uid token=token %} to {% url 'users:password_reset_confirm' uidb64=uid token=token %}. Now i'm almost certain that i'm just writing my urls or regexes wrong.
I have edited my question to show the new code.
I finally got it.
Here is the answer to the problem.
Now I get a ConnectionRefusedError, which means that I now only need to set up an SMTP Server for emails, and then it should work! The thing I was missing all the time was, that I wasn't pointing out what email template I wanted to use. I just set the email template as the template, so Django couldn't render it correctly. Here is the updated code for urls.py where path(r'password-reset/') is changed:
from django.urls import path, reverse_lazy
import django.contrib.auth.views as auth_views
from . import views
urlpatterns = [
# Login Page.
path(r'login/', auth_views.LoginView.as_view(
template_name='users/login.html'
),
name='login'),
# Logout Page.
path(r'logout/', views.logout_view, name='logout'),
# Registration Page.
path(r'register/', views.register, name='register'),
# Password reset page.
path(r'password-reset/', auth_views.PasswordResetView.as_view(
email_template_name='users/password_reset_email.html',
success_url=reverse_lazy('users:password_reset_done')
), name='password_reset'),
# Password reset done page.
path(r'password-reset/done/',
auth_views.PasswordResetDoneView.as_view(),
name='password_reset_done'),
# Password reset confirm page.
path(r'password-reset/confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm')
]
Everything else is correct.
I got the answer from this answer.
i'm using the django built in authentication system and in my login template i have this code :
login.html:
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
{% if user.is_authenticated%}
you are already logged in
{% else %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endif %}
{% endblock %}
but what i really want to do is to redirect the user to the home page if he tries to access login page while already logged in, but i am new to django so i don't know how to do that.
For django>=1.11 you can set redirect_authenticated_user parameter to True in its url in url_patterns to do the redirect, like this:
from django.contrib.auth import views as auth_views
urlpatterns = [
url(r'^login/', auth_views.LoginView.as_view(redirect_authenticated_user=True), name='login'),
]
read the document for more information.
and also set LOGIN_REDIRECT_URL in your setting file to your index url or its name:
LOGIN_REDIRECT_URL = '/index/'
In your `settings.py' add this:
LOGIN_REDIRECT_URL = 'index'
if the url name of your index is 'index', else put the correct url name
You can do it in your views.py file.
def login(request):
if request.method =="get":
if request.user.is_authenticated:
return render(// youre code)
Django version 1.11.5,
views.py
class SignupPage(CreateView):
form_class = forms.UserSignupForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
website/urls.py
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.contrib.auth.views import LoginView,LogoutView
from . import views
app_name = 'website'
urlpatterns = [
url(r'^login/', auth_views.LoginView.as_view(template_name='signin_2_w.html'), name='login'),
url(r'^logout/$', auth_views.LogoutView.as_view(), name='logout'),
url(r'^signup/', views.SignupPage.as_view(), name='sign_up'),
forms.py
class UserSignupForm(UserCreationForm):
class Meta:
fields = ('username','email','password1','password2')
model = get_user_model()
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = "Display Name"
self.fields['email'].label = "Email Address"
self.fields['password1'].label = "Password"
self.fields['password2'].label = "Confirm Password"
proj/urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.HomePage.as_view(),name='home'),
url(r'^website/',include('website.urls',namespace='website')),
url(r'^website/',include('django.contrib.auth.urls')),
url(r'^website/',views.StreamyePage.as_view(),name='streamye'),
url(r'^thanks/$',views.ThanksPage.as_view(),name='thanks'),
url(r'^congrats/$',views.CongratsPage.as_view(),name='congrats'),
url(r'^aboutus/$',views.AboutusPage.as_view(),name='about_us'),
HTML
<ul class="nav navbar-nav navbar-right">
{% if user.is_authenticated %}
<li>Logout</li>
{% else %}
<li>Login</li>
<li>Signup</li>
{% endif %}
</ul>
In the above code, the signup page is throwing me a error -- "django.urls.exceptions.NoReverseMatch: Reverse for 'sign_up' not found. 'sign_up' is not a valid view function or pattern name."
Please someone help me out where im wrong!
Thanks in advance!
You have to fix the links in the template to target the website urls :
{% if user.is_authenticated %}
<li>Logout</li>
{% else %}
<li>Login</li>
<li>Signup</li>
{% endif %}
In my case, the reason was that the session cookie was corrupted due to code changes.
I solved it by opening my app url in the incognitio mode(which will create fresh session cookie),
Then try non-incognitio normal url login.
If you are using Django rest framework, this may help.
When you have router as,
router.register("path", SomeViewSet, basename="some-name")
Call the reverse as,
reverse("some-name-list")