最近、Djangoプロジェクトドキュメント:に基づいてadmin.pyを作成しました。
https://docs.djangoproject.com/en/dev/topics/auth/customizing/#Django.contrib.auth.models.AbstractBaseUser
しかし、管理者がユーザーのパスワードを変更できる機能を本当に見逃していました。この機能を追加するにはどうすればよいですか?上記のリンクにあるコードをコピーして貼り付けました。
from Django import forms
from Django.contrib import admin
from Django.contrib.auth.models import Group
from Django.contrib.auth.admin import UserAdmin
from Django.contrib.auth.forms import ReadOnlyPasswordHashField
from customauth.models import MyUser
class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = MyUser
fields = ('email', 'date_of_birth')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = MyUser
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class MyUserAdmin(UserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'date_of_birth', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('date_of_birth',)}),
('Permissions', {'fields': ('is_admin',)}),
('Important dates', {'fields': ('last_login',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'date_of_birth', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
# Now register the new UserAdmin...
admin.site.register(MyUser, MyUserAdmin)
# ... and, since we're not using Django's builtin permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
[UPDATE-追加情報]次の情報を変更しましたが、読み取り専用フィールドにパスワード(暗号化)のみが表示されます。パスワードを変更するためのリンクを追加するにはどうすればよいですか?
fieldsets = (
('Permissions', {'fields': ('is_active', 'is_admin','password')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password')}
),
)
これをUserChangeFormに入れます。
password = ReadOnlyPasswordHashField(label= ("Password"),
help_text= ("Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using <a href=\"password/\">this form</a>."))
ここから借用したコード: http://hdknr.github.com/docs/Django/modules/Django/contrib/auth/forms.html
password = ReadOnlyPasswordHashField(label= ("Password"),
help_text= ("Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using <a href=\"../password/\">this form</a>."))
Djangoの以前のバージョンでは、hrefに変更があります。
<a href=\"/password/\">this form</a>
。
Django 1.9+ <a href=\"../password/\">this form</a>
このメソッドをUserAdmin
クラスに追加しました。
def save_model(self, request, obj, form, change):
# Override this to set the password to the value in the field if it's
# changed.
if obj.pk:
orig_obj = models.User.objects.get(pk=obj.pk)
if obj.password != orig_obj.password:
obj.set_password(obj.password)
else:
obj.set_password(obj.password)
obj.save()
通常どおりパスワードフィールドを表示できますが、管理者にはハッシュされたパスワードしか表示されません。彼らがそれを変更した場合、新しい値はハッシュされて保存されます。
これにより、管理者を介してユーザーを保存するたびに1つのクエリが追加されます。ほとんどのシステムにはユーザーを集中的に編集する管理者がいないため、通常は問題にはなりません。
('Permissions', {'fields': ('is_active', 'is_superuser',)}),
このようにすることもできます。この方法では、フィールドパスワードを上書きするだけで、保存するとハッシュが作成されます。
class UserModelAdmin(admin.ModelAdmin):
"""
User for overriding the normal user admin panel, and add the extra fields added to the user
"""
def save_model(self, request, obj, form, change):
user_database = User.objects.get(pk=obj.pk)
# Check firs the case in which the password is not encoded, then check in the case that the password is encode
if not (check_password(form.data['password'], user_database.password) or user_database.password == form.data['password']):
obj.password = make_password(obj.password)
else:
obj.password = user_database.password
super().save_model(request, obj, form, change)
Djangoバージョンに依存しないソリューションの場合、reverse
のURLをUserChangeForm.__init__
次のようなもので:
from Django.core.urlresolvers import reverse
class UserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password'].help_text = (
"Raw passwords are not stored, so there is no way to see "
"this user's password, but you can <a href=\"%s\"> "
"<strong>Change the Password</strong> using this form</a>."
) % reverse_lazy('admin:auth_user_password_change', args=[self.instance.id])