使用Django auth UserAdmin作为自定义用户模型

时间:2013-02-21 21:06:40

标签: django django-models django-admin django-authentication django-custom-user

来自Django.Contrib.Auth docs

  

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

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

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

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

6 个答案:

答案 0 :(得分:107)

在挖掘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)

答案 1 :(得分:52)

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

Ticket #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)

答案 2 :(得分:41)

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

答案 3 :(得分:5)

当我尝试在创建表单中添加自定义字段时,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 :(得分:0)

另一个类似的解决方案(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)

答案 5 :(得分:0)

只需执行以下操作

from django.contrib import admin
from .models import MyUser

admin.site.register(MyUser, admin.ModelAdmin)

就是这样。 MyUser模型的所有字段都将显示。要显示的 UserAdmin的字段列表是硬编码的(请参见其源代码),而ModelAdmin则不是。它很灵活。