使用 Django auth UserAdmin 进行自定义用户模型

问题描述 投票:0回答:7

来自 Django.Contrib.Auth 文档

扩展 Django 的默认用户 如果您对 Django 的用户模型完全满意,并且只想添加一些额外的个人资料信息,您可以简单地子类化

django.contrib.auth.models.AbstractUser
并添加自定义个人资料字段。此类提供默认 User 作为抽象模型的完整实现。

说到做到。我创建了一个如下所示的新模型:

class MyUser(AbstractUser):
  some_extra_data = models.CharField(max_length=100, blank=True)

这在管理中显示几乎就像 Django 的标准

User
。然而,admin 中最重要的区别是密码(重新)设置字段不存在,而是显示普通的 CharField。我真的必须覆盖管理配置中的内容才能使其正常工作吗?如果是这样,我怎样才能以某种干燥的方式做到这一点(即不从 Django 源代码复制内容......呃......)?

django django-models django-admin django-authentication django-custom-user
7个回答
152
投票

在深入研究 Django 源代码一段时间后,我找到了一个可行的灵魂。我对这个解决方案并不完全满意,但它似乎有效。欢迎提出更好的解决方案!


Django 使用

UserAdmin
来呈现
User
模型的良好管理外观。通过在我们的
admin.py
文件中使用它,我们可以获得相同的模型外观。

from django.contrib.auth.admin import UserAdmin
admin.site.register(MyUser, UserAdmin)

但是,仅此可能不是一个好的解决方案,因为 Django Admin 不会显示您的任何特殊字段。原因有二:

  • UserAdmin
    使用
    UserChangeForm
    作为修改对象时使用的形式,而对象又使用
    User
    作为其模型。
  • UserAdmin
    定义了
    formsets
    属性,稍后由
    UserChangeForm
    使用,其中不包括您的特殊字段。

因此,我创建了一个特殊的变更表单,它重载了 Meta 内部类,以便变更表单使用正确的模型。我还必须重载

UserAdmin
将我的特殊字段添加到字段集中,这是我有点不喜欢的解决方案的一部分,因为它看起来有点难看。欢迎提出改进建议!

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm

class MyUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        model = MyUser

class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm

    fieldsets = UserAdmin.fieldsets + (
            (None, {'fields': ('some_extra_data',)}),
    )


admin.site.register(MyUser, MyUserAdmin)

62
投票

更简单的解决方案,admin.py:

from django.contrib.auth.admin import UserAdmin
from main.models import MyUser

class MyUserAdmin(UserAdmin):
    model = MyUser

    fieldsets = UserAdmin.fieldsets + (
            (None, {'fields': ('some_extra_data',)}),
    )

admin.site.register(MyUser, MyUserAdmin)

Django 将正确引用 MyUser 模型进行创建和修改。 我正在使用 Django 1.6.2。


58
投票

nico 的回答非常有帮助,但我发现 Django 在创建新用户时仍然引用 User 模型。

票证#19353引用了这个问题。

为了解决这个问题,我必须添加一些内容

admin.py

admin.py:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from main.models import MyUser
from django import forms


class MyUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        model = MyUser


class MyUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = MyUser

    def clean_username(self):
        username = self.cleaned_data['username']
        try:
            MyUser.objects.get(username=username)
        except MyUser.DoesNotExist:
            return username
        raise forms.ValidationError(self.error_messages['duplicate_username'])


class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm
    add_form = MyUserCreationForm
    fieldsets = UserAdmin.fieldsets + (
        (None, {'fields': ('extra_field1', 'extra_field2',)}),
    )

admin.site.register(MyUser, MyUserAdmin)

13
投票
当我尝试向创建表单添加自定义字段时,

cesc 的答案对我不起作用。也许自 1.6.2 以来它已经改变了?无论哪种方式,我发现将字段添加到两个字段集和 add_fieldsets 都可以解决问题。

ADDITIONAL_USER_FIELDS = (
    (None, {'fields': ('some_additional_field',)}),
)

class MyUserAdmin(UserAdmin):
    model = MyUser

    add_fieldsets = UserAdmin.add_fieldsets + ADDITIONAL_USER_FIELDS
    fieldsets = UserAdmin.fieldsets + ADDITIONAL_USER_FIELDS

admin.site.register(MyUser, MyUserAdmin)

4
投票

如果您想挂钩到默认部分而不是复制和粘贴 Django 核心代码,您可以扩展

UserAdmin
类并将字段注入到
fieldsets
属性中。

在 Django v4.0.x 中,您正在修改的

fieldsets
元组如下所示:

    fieldsets = (
        (None, {"fields": ("username", "password")}),
        (_("Personal info"), {"fields": ("first_name", "last_name", "email")}),
        (
            _("Permissions"),
            {
                "fields": (
                    "is_active",
                    "is_staff",
                    "is_superuser",
                    "groups",
                    "user_permissions",
                ),
            },
        ),
        (_("Important dates"), {"fields": ("last_login", "date_joined")}),
    )

来源:https://github.com/django/django/blob/stable/4.0.x/django/contrib/auth/admin.py#L47-L63

现在,例如,添加自定义

role
字段:

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


class UserAdmin(BaseUserAdmin):
    fieldsets = BaseUserAdmin.fieldsets
    fieldsets[0][1]['fields'] = fieldsets[0][1]['fields'] + (
        'role',
    )


admin.site.register(User, UserAdmin)

3
投票

另一个类似的解决方案(从这里获取):

from __future__ import unicode_literals

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _

from .models import User


class UserAdminWithExtraFields(UserAdmin):

    def __init__(self, *args, **kwargs):
        super(UserAdminWithExtraFields, self).__init__(*args, **kwargs)

        abstract_fields = [field.name for field in AbstractUser._meta.fields]
        user_fields = [field.name for field in self.model._meta.fields]

        self.fieldsets += (
            (_('Extra fields'), {
                'fields': [
                    f for f in user_fields if (
                        f not in abstract_fields and
                        f != self.model._meta.pk.name
                    )
                ],
            }),
        )


admin.site.register(User, UserAdminWithExtraFields)

0
投票

再一个简单的类似情况

# models.py
class User(AbstractUser):
    age = models.PositiveSmallIntegerField(_("Age"), default=0, blank=True)
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import User


@admin.register(User)
class UserAdmin(UserAdmin):
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'age')
# settings.py
...
AUTH_USER_MODEL = "myapp.User"
...
© www.soinside.com 2019 - 2024. All rights reserved.