首页 > 解决方案 > 对自定义 Django 用户模型的任何更改都在 Admin 中完全被忽略

问题描述

我通过扩展 AbstractUser 而不是 AbstractBaseUser 自定义了 User 模型,因为我不需要删除用户名,我只需要通过电子邮件对用户进行身份验证,我仍然想使用 Django 附带的身份验证系统。因此,我只是将电子邮件地址定义为用户名,并在任何迁移之前扩展了 AbstractUser。

但是管理员没有认识到这一点,并且完全忽略了我在 admin.py 中指定的内容,除了注册指令。这是我的 admin.py 的内容

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin

from .models import User as CustomUser
from .forms import UserChangeForm, UserCreationForm
# from django.utils.translation import ugettext_lazy as _

# I obviously tried by extending UserAdmin too, no result
class CustomUserAdmin(admin.ModelAdmin):
    add_form = UserCreationForm
    form = UserChangeForm
    model = CustomUser

    fields = ('email')
    # commenting or uncommenting the following doesn't change anything
    """
    list_display = ('email', 'is_staff', 'is_active',)
    list_filter = ('email', 'is_staff', 'is_active',)

    exclude = ('first_name',)

    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Permissions', {'fields': ('is_staff', 'is_active')}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
        ),
    )
    search_fields = ('email',)
    ordering = ('email',)
    """


admin.site.register(CustomUser, BaseUserAdmin)

我尝试了一切,但没有任何效果。我无法在“添加用户”表单中添加电子邮件字段,也无法从http://127.0.0.1:8000/admin/users/user/中删除名字和姓氏

似乎 Django 内置 Admin 忽略了在扩展 AbstractUser 的任何类中所做的任何更改

显然,settings.py 中的一切都是正确的:

INSTALLED_APPS = [
    'users',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

# this is necessary for the custom user model and must to be taken into account before any migration will occur. 
AUTH_USER_MODEL = 'users.User'

模型.py:

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _


class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifier for 
    authentication instead of username.
    Between the username field (email) and password, you must put all
    the required fields. extra_fields must contain all the optional 
    fields.
    """
    def create_user(self, email, username, password, **extra_fields):
        """
        Create and save a User with the given email and password.
        """
        if not email:
            raise ValueError(_('The Email must be set'))
        if not username:
            raise ValueError("Users must have an Username")

        user = self.model(
            email = self.normalize_email(email),
            username=username, 
        )
        user.set_password(password)
        user.save()
        return user
    
    def create_superuser(self, email, username, password):
        user = self.create_user(
            email=email,
            username=username,
            password=password
        )
        user.is_admin = True
        user.is_staff=True
        user.is_superuser=True
        user.save(using=self._db)
        return user

"""
This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises. This is the recommended behavior
"""

class User(AbstractUser):
    email = models.EmailField(_('email address'), unique=True)
    USERNAME_FIELD = 'email'

    """
    The REQUIRED_FIELDS = ['username'] must be present, otherwise the following error will arise:
        TypeError: create_superuser() missing 1 required positional argument: 'username'
    """
    REQUIRED_FIELDS = ['username']
    objects = CustomUserManager()

    def getEmailField(self):
        return self.email

    def __str__(self):
        return self.email

表格.py:

class UserChangeForm(auth_forms.UserChangeForm):
    class Meta(auth_forms.UserChangeForm.Meta):
        model = CustomUser
        fields = '__all__'


class UserCreationForm(auth_forms.UserCreationForm):
    class Meta(auth_forms.UserCreationForm.Meta):
        model = CustomUser
        fields = '__all__'

显然,我在 fields = 'whatever' 中尝试了几件事,但我尝试的任何更改都被愉快地忽略了,管理员将始终以与默认方式相同的方式显示数据和表单。

我的看法.py.......

from django.shortcuts import render, redirect
from django.urls import reverse
from django.contrib.auth import login
from users.forms import CustomUserCreationForm
from django.template import RequestContext

def dashboard(request):
    return render(request, "users/dashboard.html")

def register(request):
    if request.method == "GET":
        return render(
            request, "users/register.html",
            {"form": CustomUserCreationForm}
        )
    elif request.method == "POST":
        form = CustomUserCreationForm(request.POST)
        
        if form.is_valid():
            # the form.cleaned_data must be used after calling 
            # the form.is_valid method. 
            # if(email_matches(form.cleaned_data["email"], form.cleaned_data["email2"])):
            user = form.save()
            login(request, user)
            return redirect(reverse("dashboard"))
            
        context = {
            "form": form,
        }
        return render(request, "users/register.html", context)

def home_page(request):
    return render(request, "home_page.html")

我在某处读到无法覆盖 AbstractUser 类中的任何内容,为此,我必须直接扩展 AbstractBaseUser 类。

这对管理表格也有效吗?毕竟,我并没有覆盖任何东西,我只是想在“管理员添加用户”表单中显示电子邮件地址。

但是假设我不能真正定制来自 AbstractUser 的任何东西。为什么会这样?这不是今天的问题。我已经尝试了解这种行为一个多星期了,文档和互联网都没有任何帮助。

标签: djangodjango-modelsdjango-rest-frameworkdjango-viewsdjango-admin

解决方案


而不是扩展admin.ModelAdminfor CustomUserAdmin,你应该做这样的事情 -

class CustomUserAdmin(BaseUserAdmin):
    ...
    ...

然后请像这样更正您的模型注册行-

admin.site.register(CustomUser, CustomUserAdmin)

PS 不要忘记取消注释您已评论的行。


推荐阅读