Использую базовую CBV для удаления пользователя (
django.views.generic.edit.DeleteView
). По умолчанию он использует пустую форму, а я хочу чтобы пользователь вводил подтверждение удаления с помощью пароля, т.е. мне нужно определить собственную форму и присвоить ее переменной класса
form_class
.
Я попробовал сделать форму, ориентируясь на
AuthenticationForm
:
class DeleteUserForm(forms.Form):
"""Форма для удаления пользователя с подтвреждением при помощи пароля."""
password = forms.CharField(
label="Пароль",
strip=False,
widget=forms.PasswordInput(attrs={"autocomplete": "current-password"}),
)
def __init__(self, request=None, *args, **kwargs):
"""
The 'request' parameter is set for custom auth use by subclasses.
The form data comes in via the standard 'data' kwarg.
"""
self.request = request
self.user_cache = None
super().__init__(*args, **kwargs)
def clean(self):
username = self.request.user.username
password = self.cleaned_data.get("password")
if username is not None and password:
self.user_cache = authenticate(
self.request, username=username, password=password
)
if self.user_cache is None:
raise self.get_invalid_login_error()
else:
self.confirm_login_allowed(self.user_cache)
return self.cleaned_data
Т.е. я скопировал clear заменив
username = self.cleaned_data.get("username")
на
username = self.request.user.username
. Т.е. я добавил только поле
password
для ввода, а
username
хотел брать из
self.request
. Но, как оказалось request в таком случае -
None
. Соответственно возникает ошибка
AttributeError: 'NoneType' object has no attribute 'user'.
Сделал как в LoginView - переопределил
get_form_kwargs()
моей Вью:
class UserDeleteView(OwnerTestMixin, DeleteView):
"""Класс-представление для удаление отдельного пользователя."""
model = User
form_class = DeleteUserForm
pk_url_kwarg = "user_id"
success_url = reverse_lazy('all_users')
template_name = "users/delete.html"
error_message = "У вас нет прав для удаления другого пользователя."
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["request"] = self.request
return kwargs
Также я скопировал методы
get_invalid_login_error()
(в которой изменил
params={"username": self.username_field.verbose_name} на
params={"username": self.request.user.username} и
confirm_login_allowed()
из
AuthenticationForm
. В итоге получилось это:
class DeleteUserForm(forms.Form):
"""Форма для удаления пользователя с подтврждением при помощи пароля."""
password = forms.CharField(
label="Пароль",
strip=False,
widget=forms.PasswordInput(attrs={"autocomplete": "current-password"}),
)
error_messages = {
"invalid_login":
"Please enter a correct %(username)s and password. Note that both "
"fields may be case-sensitive."
,
"inactive": "This account is inactive.",
}
def __init__(self, request=None, *args, **kwargs):
"""
The 'request' parameter is set for custom auth use by subclasses.
The form data comes in via the standard 'data' kwarg.
"""
self.request = request
self.user_cache = None
super().__init__(*args, **kwargs)
def clean(self):
username = self.request.user.username
password = self.cleaned_data.get("password")
if username is not None and password:
self.user_cache = authenticate(
self.request, username=username, password=password
)
if self.user_cache is None:
raise self.get_invalid_login_error()
else:
self.confirm_login_allowed(self.user_cache)
return self.cleaned_data
def confirm_login_allowed(self, user):
"""
Controls whether the given User may log in. This is a policy setting,
independent of end-user authentication. This default behavior is to
allow login by active users, and reject login by inactive users.
If the given user cannot log in, this method should raise a
``ValidationError``.
If the given user may log in, this method should return None.
"""
if not user.is_active:
raise ValidationError(
self.error_messages["inactive"],
code="inactive",
)
def get_invalid_login_error(self):
return ValidationError(
self.error_messages["invalid_login"],
code="invalid_login",
params={"username": self.request.user.username},
)
И это вроде работает.
Но я более чем уверен, что это, мягко говоря, неправильно. Подскажите, как нужно было сделать?
Спасибо за потраченное на меня время.