Кодирование Django - Почему необходимо возвращать два одинаковых аргумента? - PullRequest
1 голос
/ 17 октября 2019

Я хочу добавить подтверждение учетной записи электронной почты в Django и нашел хороший открытый исходный код, который я могу принять. Но есть одна строка, с которой я не знаком.

Почему функция "password_reset_confirm" должна возвращать два ** kwargs в отдельных скобках и как каждый из них используется в классе "PasswordResetConfirm"?

Этот вопрос может быть связан с Python, а не с Django. Но в любом случае, спасибо за вашу помощь!

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})/$",views.password_reset_confirm, name="reset- 
password-confirm",)

views.py

from django.contrib.auth import views as django_views

class PasswordResetConfirm(django_views.PasswordResetConfirmView):
    template_name = "account/password_reset_from_key.html"
    success_url = reverse_lazy("account:reset-password-complete")
    token = None
    uidb64 = None

    def form_valid(self, form):
        response = super(PasswordResetConfirm, self).form_valid(form)
        account_events.customer_password_reset_event(user=self.user)
        return response

def password_reset_confirm(request, uidb64=None, token=None):
    kwargs = {
        "template_name": "account/password_reset_from_key.html",
        "success_url": reverse_lazy("account:reset-password-complete"),
        "token": token,
        "uidb64": uidb64,
    }
    return PasswordResetConfirm.as_view(**kwargs)(request, **kwargs)

1 Ответ

0 голосов
/ 17 октября 2019

Первая переменная (uidb64) - это просто код пользователя в кодировке base64, извлеченный из базы данных. С помощью этого поля Django может определить, какой пользователь запрашивает сброс пароля.

Вторая переменная (token) является токеном сброса, который используется для проверки запроса пользователя. Пользователь может получить этот токен только из электронной почты, которая была ему отправлена, поэтому он проверяет, что у пользователя есть доступ к предоставленному адресу электронной почты, поэтому мы можем приступить к сбросу пароля.

Почему мы не можем использовать только token? Для этого есть две причины

  1. Django не хранит токены сброса пароля в базе данных. Многие другие фреймворки будут делать это, и после того, как пользователь нажмет URL сброса пароля, токен будет найден в базе данных, и из этой записи базы данных будет определен пользователь, запрашивающий сброс. Вместо этого Django использует некоторые умные методы криптографии и генерирует этот токен из SECRET_KEY, хранящегося в базе данных, текущего хэша пароля пользователя и времени генерации этого токена. После этого из токена можно извлечь только время, и, извлекая данные пользователя вместе с SECRET_KEY из настроек, Django может проверить, что токен сброса пароля действителен для указанного пользователя. Время генерации токена уже здесь, поэтому срок действия каждого токена может истечь через некоторое время.
  2. Идентификатор пользователя не может быть легко встроен в токен, как и время, так как формат идентификатора пользователя может быть настроен (вы можете встроить свою собственную модель пользователякоторый использует, например, 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",
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...