88

来自Django.Contrib.Auth 文档

扩展 Django 的默认用户 如果您对 Django 的用户模型非常满意并且只想添加一些额外的配置文件信息,您可以简单地继承django.contrib.auth.models.AbstractUser并添加您的自定义配置文件字段。此类提供默认用户的完整实现作为抽象模型。

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

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

这几乎像 Django 的标准一样显示在 admin 中User。但是,admin 中最重要的区别是密码(重新)设置字段不存在,而是显示了一个普通的 CharField。我真的必须覆盖 admin-config 中的内容才能使其正常工作吗?如果是这样,我怎么能以某种干燥的方式做到这一点(即不从 Django 源代码复制东西...... eww......)?

4

5 回答 5

143

在研究了 Django 源代码一段时间后,我发现了一个工作灵魂。我对这个解决方案并不完全满意,但它似乎有效。随时提出更好的解决方案!


Django 用于UserAdminUser模型呈现漂亮的管理员外观。通过在我们的admin.py-file 中使用它,我们可以获得相同的模型外观。

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

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

  • UserAdmin用作修改对象时使用UserChangeForm的形式,而对象又User用作其模型。
  • UserAdmin定义了一个formsets-property,稍后由 使用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)
于 2013-02-21T22:55:33.977 回答
58

一个更简单的解决方案,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。

于 2014-04-14T15:08:28.137 回答
57

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

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

为了修复它,我不得不再添加一些admin.py

管理员.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)
于 2013-07-05T21:04:50.920 回答
11

当我尝试将自定义字段添加到创建表单时,cesc 的答案对我不起作用。也许它自 1.6.2 以来发生了变化?无论哪种方式,我发现将字段添加到 fieldset 和 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)
于 2017-08-15T20:38:56.720 回答
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)
于 2018-08-04T19:52:19.093 回答