eksoo
eksoo

Reputation: 111

how to pass extra parameter to django rest custom action inside the viewset?

@action(detail=True, methods=['get'], url_path='password-reset/<uid64>/<token>', url_name='password-reset-confirm')
    def password_reset(self, request, uid64, token):
        pass

this is the url ( http://localhost:8000/user/2/password-reset/Mg/az44bk-48c221372ceaca98b4090a421131d5f3 ) I am trying to reach, but it keeps returning 404 page not found

Update::

urls file:

from django.urls import path
from django.urls.conf import include
from .views import UserViewset, CompanyViewset, ProfileViewset
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('user', UserViewset, basename='user')
router.register('company', CompanyViewset, basename='company')
router.register('profile', ProfileViewset, basename='profile')

urlpatterns = [
    path('', include(router.urls)),
    path('<int:id>', include(router.urls)),
]

views file:

@action(detail=True, methods=['post'], url_path='request-reset-email', url_name='request-reset-email')
    def request_reset_password_email(self, request, pk):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        email = serializer.data.get('email')
        user = self.get_object()
        if email == user.email:
            token = PasswordResetTokenGenerator().make_token(user)
            current_site = get_current_site(request=request).domain
            relativeLink = '/user/' + str(user.id) + '/password-reset/' + token
            absurl = 'http://'+current_site + relativeLink
            email_body = 'Hello \n Use link below to reset your password \n' + absurl
            subject = 'Reset your password'
            send_mail(subject, email_body, EMAIL_HOST_USER, [
                      user.email], fail_silently=False)

            return Response({'success': 'we have sent you an email'}, status=status.HTTP_200_OK)
        return Response({'failed': 'email does not match'}, status=status.HTTP_404_NOT_FOUND)



@action(detail=True, methods=['patch'], url_path=r'password-reset/(?P<token>\w+)', url_name='password-reset-confirm')
    def set_new_password(self, request, pk, token):
        user = self.get_object()
        if not PasswordResetTokenGenerator().check_token(user, 'az569s-6ad4e11c2f56aa496128bc1c923486cb'):
            return Response({'error': 'Token is not valid'}, status=status.HTTP_401_UNAUTHORIZED)

        serializer = self.get_serializer(data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        password = serializer.data.get('password')
        user.set_password(password)
        user.save()

        return Response({'success': 'success'})

serializers

    class ResetPasswordEmailRequestSerializer(serializers.Serializer):
        email = serializers.EmailField()

    class SetNewPasswordSerializer(serializers.Serializer):
        password = serializers.CharField(min_length=6, max_length=20)

Recently I have removed the uid64 since I am not using it, tested everything and it does work when hardcode the token in the url

Upvotes: 5

Views: 4062

Answers (1)

Brian Destura
Brian Destura

Reputation: 12068

Try this:

    @action(
        detail=True, 
        methods=['get'], 
        url_path=r'password-reset/(?P<uid64>\w+)/(?P<token>\w+)', 
        url_name='password-reset-confirm'
    )
    def password_reset(self, request, pk, uid64, token):
        pass

You will have to capture the three parameters: pk, uid64, and token

Upvotes: 6

Related Questions