Первая переменная (uidb64
) - это просто код пользователя в кодировке base64, извлеченный из базы данных. С помощью этого поля Django может определить, какой пользователь запрашивает сброс пароля.
Вторая переменная (token
) является токеном сброса, который используется для проверки запроса пользователя. Пользователь может получить этот токен только из электронной почты, которая была ему отправлена, поэтому он проверяет, что у пользователя есть доступ к предоставленному адресу электронной почты, поэтому мы можем приступить к сбросу пароля.
Почему мы не можем использовать только token
? Для этого есть две причины
- Django не хранит токены сброса пароля в базе данных. Многие другие фреймворки будут делать это, и после того, как пользователь нажмет URL сброса пароля, токен будет найден в базе данных, и из этой записи базы данных будет определен пользователь, запрашивающий сброс. Вместо этого Django использует некоторые умные методы криптографии и генерирует этот токен из
SECRET_KEY
, хранящегося в базе данных, текущего хэша пароля пользователя и времени генерации этого токена. После этого из токена можно извлечь только время, и, извлекая данные пользователя вместе с SECRET_KEY
из настроек, Django может проверить, что токен сброса пароля действителен для указанного пользователя. Время генерации токена уже здесь, поэтому срок действия каждого токена может истечь через некоторое время. - Идентификатор пользователя не может быть легко встроен в токен, как и время, так как формат идентификатора пользователя может быть настроен (вы можете встроить свою собственную модель пользователякоторый использует, например, UUID вместо числового значения). Вот почему Django кодирует этот идентификатор с помощью Base64 - это гарантирует, что любой формат идентификатора пользователя может быть легко встроен в URL. По этой причине идентификатор пользователя может иметь различную длину и формат, поэтому будет нелегко извлечь его из строки токена.
Что касается двойной передачи kwargs, вот краткое объяснение на примере:
В python вы можете вернуть функцию из вызова любой другой функции или метода (чаще всего такие функции называются фабриками):
def some_factory():
def some_function():
print('abc')
return some_function
my_function = some_factory()
В этом примере print вызываться не будетпоскольку мы не выполняем some_function
, some_factory
возвращает его, поэтому мы можем использовать его позже:
my_function()
Теперь будет вызван этот print, и мы увидим abc
в выводе консоли. Но вместо того, чтобы назначать возвращаемую функцию какой-либо переменной или передавать ее куда-либо, вы можете вызвать ее немедленно:
some_factory()()
Вот откуда взялись вторые скобки. Конечно, обе функции могут принимать некоторые аргументы, тогда вы предоставите аргументы для фабрики в первой паре скобок и аргументы для some_function
во вторую.
Вернемся к вашему примеру, это на самом деле неверно, вы не должныпередать полный kwargs as_view
в PasswordResetConfirm
. Должно быть только первые два (template_name
и success_url
). Фактическое представление (вторые скобки) должно занимать две другие (token
и uidb64
).
2-я вещь, которая неверна в вашем коде, это то, что вы звоните as_view
при каждом запросе. Он предназначен для вызова только один раз при создании этого представления. Вместо того, чтобы оборачивать его в отдельную функцию, используйте его прямо в вашем urls.py
:
url(
r"^password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$",
PasswordResetConfirm.as_view(
template_name="account/password_reset_from_key.html"
success_url=reverse_lazy("account:reset-password-complete"),
), name="reset-password-confirm",
)