web-dev-qa-db-fra.com

Django 2, python 3.4 ne peut pas décoder urlsafe_base64_decode (uidb64)

j'essaye d'activer un utilisateur par email, email fonctionne, encodage fonctionne, j'ai utilisé une approche de Django1.11 qui fonctionnait avec succès.

Dans Django 1.11, les décodages suivants ont réussi à 28, où uidb64 = b'Mjg '

force_text(urlsafe_base64_decode(uidb64))

Dans Django 2 (2, 0, 0, 'final', 0) le décodage de code ci-dessus ne fonctionne pas et entraîne une erreur

Django.utils.encoding.DjangoUnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 1: invalid continuation byte. You passed in b'l\xc8\xe0' (<class 'bytes'>)

Je poste également mes opinions au cas où

from Django.utils.encoding import force_bytes, force_text
from Django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode    
def signup(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False
            user.save()
            # auth_login(request, user)
            message = render_to_string('user_activate_email.html', {
                'user': user,
                'domain': Site.objects.get_current().domain,
                'uidb64': urlsafe_base64_encode(force_bytes(user.pk)),
                'token': account_activation_token.make_token(user),
            })
            mail_subject = 'Activate your blog account.'
            to_email = form.cleaned_data.get('email')
            email = EmailMessage(mail_subject, message, to=[to_email])
            email.send()
            messages.info(
                request, 'Activation link has been sent to your email!')
            # return redirect('home')
            return render(request, 'index.html')
    else:
        form = SignUpForm()
        return render(request, 'user_action.html', {'form': form})


def activate(request, uidb64, token):
    try:
        import pdb;
        pdb.set_trace()
        uid = urlsafe_base64_decode(uidb64).decode()
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError):
        user = None
    if user is not None and account_activation_token.check_token(user, token):

        user.refresh_from_db()
        user.is_active = True

        user.save()
        auth_login(request, user)
        messages.info(request, 'Your account has been activated successfully!')
        return redirect('events:home')
    else:
        messages.info(
            request, 'Activation link is invalid or has been activated')
        return redirect('events:home')

PS: Ce n'est qu'un essai avant de travailler avec CBV.

modifier: y compris traceback

System check identified no issues (0 silenced).
December 15, 2017 - 05:51:01
Django version 2.0, using settings 'event_management.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
> /home/vipinmohan/Django2-0/event/event_management/users/views.py(88)activate()
-> uid = urlsafe_base64_decode(uidb64).decode()
(Pdb) n
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcc in position 1: invalid continuation byte
> /home/vipinmohan/Django2-0/event/event_management/users/views.py(88)activate()
-> uid = urlsafe_base64_decode(uidb64).decode()
(Pdb) n
> /home/vipinmohan/Django2-0/event/event_management/users/views.py(90)activate()
-> except(TypeError, ValueError, OverflowError):
(Pdb) n
> /home/vipinmohan/Django2-0/event/event_management/users/views.py(91)activate()
-> user = None
(Pdb) 
15
Vipin Mohan

D'accord. après une longue recherche d'une heure (toujours débutant à python Django), un changement pertinent a été signalé dans les notes de version dont les définitions étaient peu difficiles pour un nouveau venu. https: //docs.djangoproject. com/fr/2.0/releases/2.0/# supprimé-support-pour-bytestrings-dans-certains-endroits

Pour prendre en charge les chaînes natives Python 2, les anciennes versions Django devaient accepter les chaînes de bytestrings et les chaînes unicode. Maintenant que Python 2 la prise en charge est supprimée, les bytestrings ne devraient être rencontrés que autour des limites d'entrée/sortie (gestion des champs binaires ou des flux HTTP, par exemple). Vous devrez peut-être mettre à jour votre code pour limiter l'utilisation des bytestring au minimum, comme Django n'accepte plus les bytestrings dans certains chemins de code.

Par exemple, reverse () utilise désormais str () au lieu de force_text () pour contraindre les arguments et les kwargs qu'il reçoit, avant leur placement dans l'URL. Pour les bytestrings, cela crée une chaîne avec un préfixe b indésirable ainsi que des guillemets supplémentaires (str (b'foo ') est "b'foo'"). Pour s'adapter, appelez decode () sur le bytestring avant de le passer à reverse ().

Totalement incapable de travailler sur ses implications, j'ai dû approfondir le code de base Django).

Donc, de Django 1.11 à 2.0, le changement d'encodage est le suivant

'uid': urlsafe_base64_encode(force_bytes(user.pk)),

à

'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),

et décoder à partir de

uid = force_text(urlsafe_base64_decode(uidb64))

à

 uid = urlsafe_base64_decode(uidb64).decode()

C'est tout. J'espère que cela aide quelqu'un.

*************ÉDITER******************

À partir de Django 2.2

Django.utils.http.urlsafe_base64_encode() retourne maintenant une chaîne au lieu d'une chaîne de bytest.

Et Django.utils.http.urlsafe_base64_decode() ne peut plus passer de bytestring.

Merci à Hillmark de l'avoir signalé

42
Vipin Mohan