Смена пароля в Django Admin

Недавно я создал admin.py на основе документа проекта Django:

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)

[ОБНОВЛЕНИЕ - Добавлена ​​информация] Я изменил следующую информацию, но по-прежнему вижу только пароль (зашифрованный) в поле, доступном только для чтения. Как можно добавить ссылку для смены пароля?

fieldsets = (
    ('Permissions', {'fields': ('is_active', 'is_admin','password')}),
)
add_fieldsets = (
    (None, {
        'classes': ('wide',),
        'fields': ('email', 'password')}
    ),
)

person Thomas    schedule 17.03.2013    source источник


Ответы (7)


Поместите это в свою форму 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>."))
person kufudo    schedule 26.03.2013
comment
Хммм, кто-нибудь знает, почему я получаю 404, пытаясь получить доступ к .../user/#id/password/? Что мне сделать, чтобы получить эту форму администратора для моей пользовательской модели? - person Dustin; 18.02.2014
comment
Нашел свой ответ: если ваша пользовательская модель пользователя расширяет django.contrib.auth.models.AbstractUser, вы можете использовать существующий класс Django django.contrib.auth.admin.UserAdmin. Однако, если ваша модель User расширяет AbstractBaseUser, вам необходимо определить собственный класс ModelAdmin. Можно создать подкласс стандартного django.contrib.auth.admin.UserAdmin; однако вам потребуется переопределить любое из определений, которые относятся к полям в django.contrib.auth.models.AbstractUser, которых нет в вашем пользовательском классе User. - person Dustin; 19.02.2014
comment
Соглашаться. Мне просто нужно изменить последнюю строку для этой: 'using <a href=\'../password/\'>this form</a>.' в django 1.9.1 Обратите внимание на ../ перед «паролем» - person oskargicast; 21.01.2016
comment
Спасибо @oskargicast за ваш комментарий, он помогает мне с версией 1.9. - person neosergio; 15.04.2016
comment
Вы не возражаете, если я спрошу, куда я должен поместить UserChangeForm? Если бы вы могли привести пример... Спасибо - person Tom Brock; 28.09.2016
comment
Отлично, спасибо @kufudo! И @oskargicast, спасибо за ../ - person LanfeaR; 25.02.2018
comment
Я не могу добиться успеха в django 2.1. Что еще нужно изменить? - person Twimnox; 21.05.2019

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>."))

В href есть изменения, для предыдущих версий django вы можете использовать

<a href=\"/password/\">this form</a>.

Для джанго 1.9+ <a href=\"../password/\">this form</a>

person Yash Rastogi    schedule 03.02.2017

Я добавил этот метод в свой класс 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()

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

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

person WhyNotHugo    schedule 28.08.2015
comment
Я только что понял, что вы можете использовать значение change, а не if obj.pk. Это упражнение предоставляется читателю. ;) - person WhyNotHugo; 28.08.2015
comment
Мне нравится это решение, поскольку оно означает, что мне не нужно возиться с формами подклассов. Вы также можете использовать form.changed_data, чтобы сделать его еще более кратким. - person Justin; 20.03.2019

Вы также можете сделать это, таким образом, вам просто нужно написать пароль поля, и как только вы его сохраните, он создаст для него хэш:

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)
person Roberto Fernandez Diaz    schedule 27.10.2019
comment
Мне нужно было поймать исключение user_database.DoesNotExist при первом создании пользователя - person j4n7; 05.02.2021

Для решения, независимого от версии 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])
person Max Peterson    schedule 13.09.2018

Вы также можете рассмотреть возможность расширения UserAdmin следующим образом:

from django.contrib import admin
from myapp.models import CustomUser
from django.contrib.auth.admin import UserAdmin

class CustomUserAdmin(UserAdmin):
    list_display = []
admin.site.register(CustomUser, CustomUserAdmin)
person Kipngetich Yegon    schedule 07.11.2020

person    schedule
comment
Здравствуйте, Екатерина, пожалуйста, смотрите мое обновление в вопросе. Я могу видеть пароль в поле только для чтения. Но я не могу выбрать новый - person Thomas; 17.03.2013
comment
@Thomas Я отслеживаю коды и обнаружил, что пароль стал доступен только для чтения из-за этого ReadOnlyPasswordHashField(). Для решения вы должны создать ссылку в поле пароля только для чтения, где она ссылается на форму смены пароля. - person catherine; 18.03.2013