NoReverseMatch с аргументом ключевого слова uidb64 с Django 2.0

Я не могу понять, почему мой код не работает. Раньше это работало, но теперь, когда я запускаю сервер и тестирую, код не работает.

Когда пользователь регистрируется, я отправляю ему активационное письмо, например:

def send_activation_email(serializer, request, user):
    current_site = get_current_site(request)
    message = render_to_string('acc_active_email.html', {
        'user': user,
        'domain': current_site.domain,
        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
        'token': account_activation_token.make_token(user),
    })
    mail_subject = 'Activate your blog account.'
    to_email = serializer.data['email']

    email = EmailMessage(mail_subject, message, to=[to_email])
    email.send()

acc_active_email.html

{% autoescape off %}
Hi {{ user.username }},
Please click on the link to confirm your registration,

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

и мой файл URL

.
.
    url(r'^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.activate_account, name='activate'),
.
.

но у меня есть эта ошибка:

Exception Type:     NoReverseMatch
Exception Value:    

Reverse for 'activate' with keyword arguments '{'uidb64': b'NDM', 'token': '4qz-8f770502bd8b02786da9'}' not found. 1 pattern(s) tried: ['activate/(?P<uidb64>[0-9A-Za-z_\\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$']

выделяет эту строку http://{{ domain }}{% url 'activate' uidb64=uid token=token %}


person r2546971    schedule 08.11.2017    source источник
comment
Интересно, не работает ли это, потому что uid - это байты. Попробуйте жестко закодировать 'uid': 'NDM', чтобы увидеть, исправит ли это ошибку.   -  person Alasdair    schedule 08.11.2017
comment
@Alasdair вау, если я установлю «uid»: «NDM» в методе send_activation_email, это сработает. Это странно   -  person r2546971    schedule 08.11.2017
comment
Хорошо, похоже, вам нужно преобразовать байты в строку, чтобы иметь возможность изменить URL-адрес.   -  person Alasdair    schedule 08.11.2017


Ответы (4)


В Django 2.0 и 2.1 вы должны вызывать decode() после того, как base64 кодирует uid, чтобы преобразовать его в строку:

message = render_to_string('acc_active_email.html', {
    'user': user,
    'domain': current_site.domain,
    'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
    'token': account_activation_token.make_token(user),
})

См. примечание в Django. примечания к выпуску 2.0 для получения дополнительной информации.

В Django 2.2+ urlsafe_base64_encode возвращает строку, поэтому нет нужно расшифровать.

message = render_to_string('acc_active_email.html', {
    'user': user,
    'domain': current_site.domain,
    'uid': urlsafe_base64_encode(force_bytes(user.pk)),
    'token': account_activation_token.make_token(user),
})

Должна быть возможность написать код, совместимый с Django ‹ 1.11, 2.0-2.1 и 2.2+, используя force_text. Обратите внимание, что следующее не проверено.

from django.utils.encoding import force_text

message = render_to_string('acc_active_email.html', {
    'user': user,
    'domain': current_site.domain,
    'uid': force_text(urlsafe_base64_encode(force_bytes(user.pk))),
    'token': account_activation_token.make_token(user),
})

Вы можете отказаться от force_text и использовать второй фрагмент кода после прекращения поддержки Django ‹ 2.2.

person Alasdair    schedule 08.11.2017

Для более новых версий Django вы можете использовать синтаксис slug. Например:

path(
    'activate/<slug:uidb64>/<slug:token>/',
    views.activate_account, 
    name='activate'
)
person lehoang    schedule 05.08.2020

Может быть, это глупо, поскольку URL-адрес не динамический, но это сработало...

path('activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', views.activate, name='activate'),
person Tinashe Mphisa    schedule 16.11.2020
comment
Уточните свой ответ, пожалуйста, для облегчения понимания. - person burningalc; 16.11.2020

Лучшие ответы здесь, но я обновил регулярное выражение для токена, сделав его длиной 32 символа.

person vfxGer    schedule 06.12.2020