Django 2,Python 3.4无法解码urlsafe_base64_decode(uidb64)

20

我正在尝试通过电子邮件激活用户,电子邮件可以正常工作,编码也可以正常工作,我使用了Django1.11的一种方法,这个方法之前成功地运行过。

在Django1.11中,以下内容成功解码为28,其中uidb64 = b'Mjg'

force_text(urlsafe_base64_decode(uidb64))

在 Django 2(版本号为 2.0.0 final)中,上述代码的解码功能不可用并会导致错误。
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'>)

我也发表一下我的看法,以防万一。

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:在我与CBV合作之前,这只是一次试验。

编辑:包括回溯信息。

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) 

1
请显示完整的回溯信息。 - Daniel Roseman
1
请问您能否具体说明您想要做什么?这个问题不太清楚,它只是陈述了一个一般性的问题。请获取您要解决的问题,并添加完整的回溯信息,这可能有助于指导您。 - Midhun Mohan
我已经包含了回溯信息。我正在尝试通过激活邮件来激活用户。当我点击链接时,它无法工作。使用pdb.set_trace(),会抛出Unicode解码错误。 - Vipin Mohan
1个回答

60

好的。在搜索了一个小时后(我仍然是Python Django的初学者),发布说明中指出了一个相关的更改,但其中的定义对新手来说有点困难。

https://docs.djangoproject.com/en/2.0/releases/2.0/#removed-support-for-bytestrings-in-some-places

为了支持本地Python 2字符串,旧版Django版本必须接受字节串和unicode字符串。现在Python 2的支持被放弃,字节串只应出现在输入/输出边界(例如处理二进制字段或HTTP流)。 您可能需要更新代码以将字节串的使用限制到最小值,因为Django不再接受某些代码路径中的字节串。

例如,reverse() 现在使用 str() 而不是 force_text() 来强制转换它接收到的 args 和 kwargs,在它们放置到URL之前。对于字节串,这会创建一个带有不需要的 b 前缀和额外引号的字符串(str(b'foo') 是 "b'foo'")。要进行适应,将字节串传递给 reverse() 之前,请对其调用 decode()。

完全无法理解它的影响,我不得不深入实际的Django核心代码。

因此,从Django 1.11到2.0的编码更改如下:

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

并从中解码

uid = force_text(urlsafe_base64_decode(uidb64))

为了

 uid = urlsafe_base64_decode(uidb64).decode()

就这样了。希望能对某些人有所帮助。

*************编辑******************

截至Django 2.2版本

django.utils.http.urlsafe_base64_encode()现在返回字符串而不是字节串。

django.utils.http.urlsafe_base64_decode()不能再传入字节串。

感谢Hillmark指出这一点。


2
从2.2版本开始更改,现在返回字符串而不是字节串。https://docs.djangoproject.com/en/2.2/releases/2.2/#miscellaneous - hillmark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接