扩展 Django 的默认用户 如果您对 Django 的用户模型非常满意并且只想添加一些额外的配置文件信息,您可以简单地继承 django.contrib.auth.models.AbstractUser 并添加您的自定义配置文件字段。此类提供默认用户的完整实现作为抽象模型。
说了又做了。我创建了一个新模型,如下所示:
class MyUser(AbstractUser):
some_extra_data = models.CharField(max_length=100, blank=True)
这几乎像 Django 的标准 User
一样显示在 admin 中。但是,admin 中最重要的区别是密码(重新)设置字段不存在,而是显示了一个普通的 CharField。我真的必须覆盖 admin-config 中的内容才能使其正常工作吗?如果是这样,我怎么能以某种干燥的方式做到这一点(即不从 Django 源代码复制东西...... eww......)?
在研究了 Django 源代码一段时间后,我发现了一个工作灵魂。我对这个解决方案并不完全满意,但它似乎有效。随时提出更好的解决方案!
Django 使用 UserAdmin
为 User
模型呈现漂亮的管理员外观。通过在我们的 admin.py
文件中使用它,我们可以获得相同的模型外观。
from django.contrib.auth.admin import UserAdmin
admin.site.register(MyUser, UserAdmin)
但是,仅此一项可能不是一个好的解决方案,因为 Django Admin 不会显示您的任何特殊字段。有两个原因:
UserAdmin 使用 UserChangeForm 作为修改对象时使用的表单,而后者又使用 User 作为其模型。
UserAdmin 定义了一个表单集属性,稍后由 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)
一个更简单的解决方案,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。
None
,您可以输入一个字符串,它将用作管理表单中部分的标题
ERRORS: <class 'users.admin.CustomerUserAdmin'>: (admin.E005) Both 'fieldsets' and 'fields' are specified.
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)
forms.ValidationError
的调用有第二个参数:code='duplicate_username'
: github.com/django/django/blob/1.6/django/contrib/auth/… 另外,我在 1.6.5 上尝试过这个,由于某种原因,我不需要在所有和更改表单都适用于我的自定义字段。我无法解释为什么。由于存在 model = User
的 UserChangeForm
类,它似乎不应该起作用:github.com/django/django/blob/1.6.5/django/contrib/auth/…
当我尝试将自定义字段添加到创建表单时,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)
另一个类似的解决方案 (Took from here):
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)
如果您想挂接到默认部分而不是复制和粘贴 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)