DjangoでUserモデル以外にパスワードを持つモデルを定義して認証したいことがあった。
admin.py
class AdminName(admin.ModelAdmin):
readonly_fields = ('password',) #1
form = MyForm
fieldsets = [
(None, {'fields':('name',)}),
(None, {'fields':('password',),'description':'id'}) #2
]
def get_object(self, request, view, object_id):
obj = super(AdminName, self).get_object(request,view, object_id) #3
if obj:
url = reverse('change_password', args=[obj.id])
# objが存在する場合、そのidを設定します
self.fieldsets[1][1]['description'] = '生のパスワードは格納されていないため、このパスワードを確認する方法はありません。\
しかし'+f'<a href="{url}">このフォーム</a>'+'を使用してパスワードを変更できます。' #4
return obj
# Register your models here.
admin.site.register(ModelName, AdminName)
#1 編集させないリードオンリーなフィールドを記述
#2 'description' で注釈をつけられる。
#3 adminサイトのchange urlに含まれるidを取得する。
#4 文字列の中にhtmlを仕込むことによりリンクを作成
forms.py
class SetPasswordForm(forms.Form):
error_messages = {
"password_mismatch": _("The two password fields didn't match."),
}
new_password1 = forms.CharField(
label=_("New password"),
widget=forms.PasswordInput(attrs={"autocomplete": "new-password", 'class': 'form-control'}),
strip=False,
help_text=password_validation.password_validators_help_text_html(),
)
new_password2 = forms.CharField(
label=_("New password confirmation"),
strip=False,
widget=forms.PasswordInput(attrs={"autocomplete": "new-password", 'class': 'form-control'}),
)
def __init__(self, index, *args, **kwargs):
self.index = index
super().__init__(*args, **kwargs)
def clean_new_password2(self):
password1 = self.cleaned_data.get("new_password1")
password2 = self.cleaned_data.get("new_password2")
if password1 and password2:
if password1 != password2:
raise ValidationError(
self.error_messages["password_mismatch"],
code="password_mismatch",
)
password_validation.validate_password(password2)
return password2
formのcleanメソッドを使用する。たくさん資料があるのでここでは説明しない。
views.py
# adminサイトのChatTypeパスワード変更
class PasswordContextMixin:
extra_context = None
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({"title": self.title, **(self.extra_context or {})})
return context
class PasswordResetView(FormView):
template_name = 'my_password_change_form.html' #1
form_class = SetPasswordForm
success_url = reverse_lazy('password_change_done')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['index'] = self.kwargs['index'] # Assuming you pass 'index' as a parameter in the URL
return kwargs
def form_valid(self, form):
index = form.index # Access the index from the form
# You can perform any additional processing or validation here if needed
# For example, you can update the user's password and log them in
col = Model.objects.get(id=index)
col.password = make_password(form.cleaned_data['new_password1']) #2
col.save()
return super().form_valid(form)
def form_invalid(self, form):
# Handle invalid form submission here if needed
return super().form_invalid(form)
class PasswordChangeDoneView(PasswordContextMixin, TemplateView): #3
template_name = "my_password_change_done.html"
title = _("Password change successful")
#1 admin標準のテンプレートを基に作成
#2 djangoのmake_passwordを用いてパスワードを暗号化
#3 パスワード変更成功後のView