Как установить пароль для модели Custom User на странице администратора Django?

Я определил пользовательскую модель пользователя, используя класс AbstractBaseUser. Ниже приведена реализация для справки.

#models.py

class UserManager(BaseUserManager):
    def create_user(self, email, firstname, lastname, contact, password):
        if not email:
            raise ValueError('You must provide an email address')
        if not contact:
            raise ValueError('You must provide a contact number')
        
        email = self.normalize_email(email)
        user = self.model(email=email, firstname=firstname, lastname=lastname, contact=contact)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, firstname, lastname, contact, password):
        user = self.create_user(email, firstname, lastname, contact, password)
        user.is_admin = True
        user.save(using=self._db)
        return user

class Users(AbstractBaseUser):
    id = models.AutoField(primary_key=True)
    firstname = models.CharField(max_length=50)
    lastname = models.CharField(max_length=50)
    contact = models.CharField(max_length=10, unique=True)
    email = models.EmailField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    is_staff = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['firstname', 'lastname', 'contact']

    objects = UserManager()

    def save(self, *args, **kwargs):
        if not self.firstname or not self.lastname or not self.contact or not self.email or not self.password:
            raise ValueError('All required fields must be provided')
        super().save(*args, **kwargs)

    def __str__(self):
        return str(self.id) + '. ' + self.firstname + ' ' + self.lastname

    def has_perm(self, perm, obj=None):
        return self.is_admin

    def has_module_perms(self, app_label):
        return True
    
    class Meta:
        db_table = 'users'
        verbose_name_plural = 'Users'

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

Вот мой код admin.py.

#admin.py

from django.contrib import admin
from .models import *

admin.site.site_header = 'ROI Administration'
admin.site.site_title = 'ROI | Admin Panel'
admin.site.index_title = 'ROI Databases'

class UsersAdmin(admin.ModelAdmin):
    ordering = ['id']
    readonly_fields = ['id', 'created_at', 'last_login']
    fieldsets = [
        (None, {'fields': ['id', 'firstname', 'lastname', 'email', 'contact', 'last_login', 'created_at', 'is_staff', 'is_admin', 'password']}),
    ]

admin.site.register(Users, UsersAdmin)

См. скриншот ниже.

enter image description here

Как мне решить эту проблему?

Вам нужно использовать специальный класс UserAdmin, как показано здесь admin.UserAdmin. Это должно решить вашу проблему

Я провел некоторое исследование и наконец решил эту проблему. Я создал CustomUserAdmin и CustomUserChangeForm в файле admin.py.

#admin.py

from .models import *
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm, AdminPasswordChangeForm
from django.template.response import TemplateResponse
from django.core.exceptions import PermissionDenied

class CustomUserChangeForm(UserChangeForm):
    class Meta:
        model = Users
        fields = '__all__'

class CustomUserAdmin(BaseUserAdmin):
    form = CustomUserChangeForm
    add_form = UserCreationForm
    ordering = ['id']
    readonly_fields = ['id', 'created_at', 'last_login']
    list_display = ['id', 'firstname', 'lastname', 'email', 'contact', 'is_staff', 'is_admin']
    fieldsets = (
        ('Credentials', {'fields': ('email', 'password')}),
        (('Personal info'), {'fields': ('firstname', 'lastname', 'contact')}),
        ('Permissions', {'fields': ('is_staff', 'is_admin')}),
        ('Important dates', {'fields': ('last_login', 'created_at')})
    )

    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'firstname', 'lastname', 'contact', 'password1', 'password2', 'is_staff', 'is_admin'),
        }),
    )

    filter_horizontal = ()
    list_filter = []

    def change_password(self, request, user_id, form_url=''):
        user = self.get_object(request, user_id)
        if not self.has_change_permission(request, user):
            raise PermissionDenied

        if request.method == 'POST':
            form = AdminPasswordChangeForm(user, request.POST)
            if form.is_valid():
                form.save()
                return self.response_change(request, user)
        else:
            form = AdminPasswordChangeForm(user)

        fieldsets = [(None, {'fields': list(form.base_fields)})]
        admin_form = admin.helpers.AdminForm(form, fieldsets, {})

        context = {
            'title': f'Change password: {user.email}',
            'adminForm': admin_form,
            'form_url': form_url,
            'form': form,
            'is_popup': "_popup" in request.POST or "_popup" in request.GET,
            'opts': self.model._meta,
            'original': user,
            'save_as': False,
            'show_save': True,
            **self.admin_site.each_context(request),
        }

        return TemplateResponse(request, 'admin/auth/user/change_password.html', context)

    def get_urls(self):
        from django.urls import path
        urls = super().get_urls()
        custom_urls = [
            path(
                '<user_id>/password/',
                self.admin_site.admin_view(self.change_password),
                name='auth_user_password_change',
            ),
        ]
        return custom_urls + urls

admin.site.register(Users, CustomUserAdmin)

Это решает проблему.

Вернуться на верх