Django 2, python 3.4 не может декодировать urlsafe_base64_decode (uidb64)
Я пытаюсь активировать пользователя по электронной почте,
работа электронной почты, работа с кодировками, я использовал подход от django1.11, который успешно работал.
В Django 1.11 следующее успешно декодируется до 28, где uidb64 = b'Mjg '
force_text(urlsafe_base64_decode(uidb64))
В django 2 (2, 0, 0, 'final', 0) вышеупомянутый декодирование кода не работает и приводит к ошибке
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.
edit: включая трассировку
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
Хорошо. после часового поиска (все еще начинающего в Python Django) было отмечено соответствующее изменение в примечаниях к выпуску, определения которых были немного сложными для новичка. https://docs.djangoproject.com/en/2.0/releases/2.0/#removed-support-for-bytestrings-in-some-places
Чтобы поддерживать нативные строки Python 2, старые версии Django должны были принимать как строки байтов, так и строки Юникода. Теперь, когда поддержка Python 2 прекращена, строки байтов должны встречаться только вокруг границ ввода/вывода (например, обработка двоичных полей или потоков HTTP). Возможно, вам придется обновить свой код, чтобы ограничить использование байтовых строк до минимума, так как Django больше не принимает байтовые строки в определенных путях кода.
Например, reverse() теперь использует str() вместо force_text() для приведения аргументов и kwargs, которые он получает, до их размещения в URL. Для строк байтов это создает строку с нежелательным префиксом b, а также дополнительные кавычки (str (b'foo ') - это "b'foo" "). Чтобы адаптироваться, вызовите decode() для строки байтов, прежде чем передавать ее в reverse().
Абсолютно не в силах разобраться с его последствиями, мне пришлось углубиться в реальный код ядра 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 за указание на это