Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dango 2.2 Reverse for 'activate' with keyword arguments

I have a problem with creating an account and activating it with the link sent in the email. The application is written in Django version 2.2.

After clicking the activation link, I receive a message:

Reverse for 'activate' with keyword arguments '{'uidb64': '', 'token': ''}' not found. 1 pattern(s) tried: ['activate/(?P<uidb64>[^/]+)/(?P<token>[^/]+)/$']

Code in urls.py

path('activate/<uidb64>/<token>/', account.activate, name='activate'),

Code in views.py, code for sign up and activate link. Signup is like a CBV and activate is like a FBV.

class Signup(View):
    def get(self, request):
        form = SignUpForm()
        return render(request, 'account/signup.html', {'form': form})

    def post(self, request):
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False
            user.save()
            current_site = get_current_site(request)
            subject = 'Activate your Spotted account'
            message = render_to_string('account/account_activation_email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'token': account_activation_token.make_token(user)
            })
            user.email_user(subject, message)
            return redirect('account_activation_sent')
        return render(request, 'account/signup.html', {'form': form})


def activate(request, uidb64, token):
    try:
        uid = force_text(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None

    if user is not None and account_activation_token.check_token(user, token):
        user.is_active = True
        user.profile.email_confirmed = True
        user.save()
        login(request, user)
        return render(request, 'account/account_activation_email.html')
    else:
        return render(request, 'account/account_activation_invalid.html')

In account/account_activation_email.html:

{% autoescape off %}
Hi {{ user.username }},

Please click on the link below to confirm your registration:

http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}

token.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six


class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.profile.email_confirmed)
        )


account_activation_token = AccountActivationTokenGenerator()
like image 794
Webdev Avatar asked Jan 02 '20 21:01

Webdev


2 Answers

In case you are using Django 3.1 or above, the activation/password reset mechanism uses the SHA-256 hashing algorithm for tokens. Your regexp is too strict. you should use path instead url like the following as per the documentation.

path('reset/<uidb64>/<token>/', ...)

path('activate/<uidb64>/<token>/', ...)

Details here

like image 109
Toufique Hasan Avatar answered Nov 11 '22 14:11

Toufique Hasan


You have to pass token and uid as context to render:

def activate(request, uidb64, token):
    ...

    context = {'uidb64':uidb64, 'token':token}
    return render(request, 'account/account_activation_email.html', context)
like image 32
Lord Elrond Avatar answered Nov 11 '22 15:11

Lord Elrond