Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django user activation doesnt work with token — TypeError: a bytes-like object is required, not 'str'

So I have the following token activation setup for users to activate their accounts

# urls.py

    # Activation
    path('activate/<uidb64>/<token>/',
         user_views.activate, name='activate'),
# views.py

User = get_user_model()  # Get custom user model

def activate(request, uidb64, token):
    # Debugging
    uid = force_bytes(urlsafe_base64_decode(uidb64))
    print(User.objects.get(pk=uid))
    try:
        uid = force_bytes(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.email_confirmed = True
        user.save()
        login(request, user)
        return redirect('/dashboard/overview/')
    else:
        return render(request, 'user/authentication/account_activation_invalid.html')
# tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
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.email_confirmed)
        )


account_activation_token = AccountActivationTokenGenerator()
# models.py
# Custom usermodel

class UserProfile(AbstractBaseUser, PermissionsMixin):

    # Unique identifier
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    # Email and name of the user
    email = models.EmailField(max_length=255, unique=True)
    name = models.CharField(max_length=255)

    # Privilege and security booleans
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)
    email_confirmed = models.BooleanField(default=False)

    objects = UserProfileManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def email_user(self, subject, message, from_email=None, **kwargs):
        """Send mail to user - Copied from original class"""
        send_mail(subject, message, from_email, [self.email], **kwargs)

    def __str__(self):
        return self.email

However, when I click the emailed link, the view always returns the isn't valid path.
Some debugging pointed me to print(User.objects.get(pk=uid)) which returns

TypeError: a bytes-like object is required, not ‘str’ [01/Sep/2022
04:18:57] "GET
/activate/MjA1ZjJjOWUtZjJmZC00ZDNlLWI5ZjktMTFiYjJiMzBkYWRm/bb210r-cb574367d34da4d3175ab454a49e6527/
HTTP/1.1" 500 132326

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Not sure what’s wrong as this setup already worked in a different project of mine.

>Solution :

probably you are need force_str
more here: https://docs.djangoproject.com/en/4.1/ref/utils/#django.utils.encoding.force_str

in your case:

user = User.objects.get(pk=uid.decode("utf-8"))

more here:
https://docs.python.org/3/library/stdtypes.html#bytes.decode

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading