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

1

5
@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

Margheritamargi answered 11/1, 2022 at 22:40 Comment(4)
Can you try with url_path='password-reset/<str:uid64>/<str:token>'Ozell
@BrianDestura I did, still not workingMargheritamargi
Oh just saw this, apparently you can only use regex expressions. Try and see if that worksOzell
@BrianDestura I've tried this url_path=r'password-reset/(?P<uid64>\w+)/(?P<token>\w+)'. I dont know if its written correctly but its not workingMargheritamargi
O
6

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

Ozell answered 12/1, 2022 at 0:43 Comment(12)
Hi again, I have tried this and it is still not working, even tho everything works perfectly fine when I hardcode the token and uid64 like this url_path='password-reset/Mg/az45wt-605ef65dedd38ed4561dbe17b1582db9'Margheritamargi
Can you update the question with the latest code you have? I tried this out locally and it works fineOzell
I did, thanks in advance for trying to help <3Margheritamargi
Ok can you also show what password_reset looks like right now? Or is that set_new_password?Ozell
oh yeah sorry forgot to mention that too, yes password_reset is set_net_password nowMargheritamargi
And are you hitting the url through a browser? If yes, then the reason why its 404 is because the method is now set to PATCH while the browser is doing a GET.Ozell
even with GET, I still get 404Margheritamargi
Did you mean you used methods=['get']?Ozell
yes methods=['get'] returns 404Margheritamargi
Finally I found the problem, for some reason (?P<token>\w+) was not picking up the dash in the token in the URL so it had to be (?P<token>[-\w]+). Thanks for your help.Margheritamargi
Oh yeah nice that's great!Ozell
For me, the problem was the URL placeholder; It was like <token> as in urlpatterns, but it should be in the form of (?P<token>\w+). Still, I don't understand what is it for, however.Rainout

© 2022 - 2024 — McMap. All rights reserved.