Django rest_framework forgot password

Viewed 1049

I'm newbie in Django I have a trouble with this: I've already make API for 'request-reset-email', 'password-reset' and 'password-reset-complete' Here are the code: file: urls.py

from django.urls import path
from .views import *
from django.contrib.auth import views as auth_view
from rest_framework_simplejwt.views import (
    TokenObtainSlidingView,
    TokenRefreshSlidingView,
)
urlpatterns=[
    path('register/', RegisterView.as_view(), name="register"),
    path('login/', LoginAPIView.as_view(), name="login"),
    path('email-verify/', VerifyEmail.as_view(), name="email-verify"),
    path('token/refresh/', TokenRefreshSlidingView.as_view(), name='token_refresh'),
    path('request-reset-email/',RequestPasswordResetEmail.as_view(), name='request-reset-email'),
    path('password-reset/<uidb64>/<token>/',PasswordTokenCheckAPIView.as_view(),name='password-reset'),
    path('password-reset-complete/',SetNewPasswordAPIView.as_view(),name='password-reset-complete')
]

file Views.py:

from django.shortcuts import render
from rest_framework import exceptions, generics, serializers
from rest_framework.response import Response
from rest_framework import status
from .models import *
from .serializers import *
from rest_framework_simplejwt.tokens import RefreshToken
from .utils import *
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
import jwt
from django.conf import settings
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils.encoding import smart_str, force_str, smart_bytes, DjangoUnicodeDecodeError
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
# Create your views here.
class RegisterView(generics.GenericAPIView):
    queryset = User.objects.all()
    serializer_class=RegisterSerializer
    def post(self, request):
        user = request.data
        serializer = self.serializer_class(data=user)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        user_data = serializer.data

        user= User.objects.get(email=user_data['email'])
        token=RefreshToken.for_user(user).access_token

        current_site=get_current_site(request).domain
        realtivelink = reverse('email-verify')
        
        absurl='http://'+current_site+realtivelink+"?token="+ str(token)
        email_body='Hi '+ user.email+ ' Use link below to verify your email \n' + absurl
        data={'email_body':email_body,'to_email':user.email,'email_subject':'Verify your email'}
        Util.send_email(data)
        return Response(user_data,status= status.HTTP_201_CREATED)

class VerifyEmail(generics.GenericAPIView):
    def get(self,request):
        token= request.GET.get('token')
        try:
            payload=jwt.decode(token,settings.SECRET_KEY,algorithms='HS256')
            user=User.objects.get(id=payload['user_id'])

            if not user.is_verified:
                user.is_verified=True
                user.save()
            return Response({'email':'Successfully activated'},status= status.HTTP_200_OK)
        except jwt.ExpiredSignatureError as indentifier:
            return Response({'email':'Activation expired'},status= status.HTTP_400_BAD_REQUEST)
        except jwt.exceptions.DecodeError as indentifier:
            return Response({'email':'Invalid token'},status= status.HTTP_400_BAD_REQUEST)


class LoginAPIView(generics.GenericAPIView):
    queryset = User.objects.all()
    serializer_class = LoginSerializers
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        return Response(serializer.data,status=status.HTTP_200_OK )

class RequestPasswordResetEmail(generics.GenericAPIView):
    queryset = User.objects.all()
    serializer_class=ResetPasswordViaEmailSerializer
    def post(self, request):

        serializer = self.serializer_class(data=request.data)
        email = request.data['email']

        if User.objects.filter(email=email).exists():
            user = User.objects.get(email=email)
            uidb64 = urlsafe_base64_encode(smart_bytes(user.id) )
            token = PasswordResetTokenGenerator().make_token(user)

            current_site=get_current_site(request=request).domain
            realtivelink = reverse('password-reset',kwargs={'uidb64':uidb64,'token':token})
                
            absurl='http://'+current_site+realtivelink
            email_body='Hi, \nUse link below to reset your password \n' + absurl
            data={'email_body':email_body,'to_email':user.email,'email_subject':'Reset your password'}
            Util.send_email(data)
        return Response({'successfully':'check your email to reset your password'},status=status.HTTP_200_OK)

class PasswordTokenCheckAPIView(generics.GenericAPIView):
    def get(self, request, uidb64,token):
        try:
            id= smart_str(urlsafe_base64_decode(uidb64))
            user= User.objects.get(id=id)
            if not PasswordResetTokenGenerator().check_token(user,token):
                return Response({'error':'token is not valid, please check the new one'},status=status.HTTP_401_UNAUTHORIZED)
            return Response({'sucess':True, 'message':'Credential Valid','uidb64':uidb64, 'token':token},status=status.HTTP_200_OK)


        except DjangoUnicodeDecodeError as indentifier:
            return Response({'error':'token is not valid, please check the new one'},status=status.HTTP_401_UNAUTHORIZED)

class SetNewPasswordAPIView(generics.GenericAPIView):
    queryset = User.objects.all()
    serializer_class=ResetPassWordSerializer

    def patch(self, request):
        serializer=self.serializer_class(data=request.data)

        serializer.is_valid(raise_exception=True)

        return Response({'sucess':True, 'message':'Password is reset successfully'},status=status.HTTP_200_OK)

APIs've already worked. But I want to make the "PasswordTokenCheckAPIView" have a templete for user to enter the new password and confirm it. So, could you please to give me some way to do this? I've tried to use django.contrib.auth.PasswordResetConfirmView, it appears the template when I click the link I received in mail, but when I confirm change password, there is error

from django.urls import path
from .views import *
from django.contrib.auth import views as auth_view
from rest_framework_simplejwt.views import (
    TokenObtainSlidingView,
    TokenRefreshSlidingView,
)
urlpatterns=[
    path('register/', RegisterView.as_view(), name="register"),
    path('login/', LoginAPIView.as_view(), name="login"),
    path('email-verify/', VerifyEmail.as_view(), name="email-verify"),
    path('token/refresh/', TokenRefreshSlidingView.as_view(), name='token_refresh'),
    path('request-reset-email/',RequestPasswordResetEmail.as_view(), name='request-reset-email'),
    path('password-reset/<uidb64>/<token>/',auth_view.PasswordResetConfirmView.as_view(),name='password-reset'),
    path('password_reset_complete/',auth_view.PasswordResetCompleteView.as_view(),name='password-reset-complete')
]

the error: Reverse for 'password_reset_complete' not found. 'password_reset_complete' is not a valid view function or pattern name.

Thank you very much!

1 Answers

Change

path('password_reset_complete/',auth_view.PasswordResetCompleteView.as_view(),name='password-reset-complete')

to

path('password_reset_complete/',auth_view.PasswordResetCompleteView.as_view(),name='password_reset_complete')

Django reverse checks for name in the path.

Related