Używanie Django auth UserAdmin dla niestandardowego modelu użytkownika

Z Django.Contrib.Auth docs :

Rozszerzenie domyślnego użytkownika Django Jeśli jesteś całkowicie zadowolony z modelu użytkownika Django i chcesz po prostu dodać dodatkowe informacje o Profilu, możesz po prostu podklasować django.contrib.auth.models.AbstractUser i dodać swoje niestandardowe pola profilu. Klasa ta zapewnia pełną implementację domyślnego użytkownika jako abstrakcyjnego modelu.

Powiedział i zrobił. Stworzyłem nowy model jak poniżej:
class MyUser(AbstractUser):
  some_extra_data = models.CharField(max_length=100, blank=True)

To pojawia się w adminie prawie jak standard Django User. Jednak najważniejszą różnicą w admin Jest to, że pole password-(re)set nie jest obecne, ale zamiast tego wyświetlane jest normalne pole CharField. Czy naprawdę muszę nadpisywać rzeczy w admin-config, aby to zadziałało? Jeśli tak, to jak Mogę to zrobić w nieco suchy sposób (tj. bez kopiowania rzeczy ze źródła Django... eww...)?

Author: Mariusz Jamro, 2013-02-22

5 answers

Po przekopaniu się przez chwilę kodu źródłowego Django, znalazłem działającą duszę. Nie jestem całkowicie zadowolony z tego rozwiązania, ale wydaje się, że działa. Zachęcamy do zaproponowania lepszych rozwiązań!


Django używa UserAdmin do renderowania ładnego wyglądu admina dla modelu User. Używając tego w pliku admin.py, możemy uzyskać ten sam wygląd naszego modelu.

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

Jednak samo to prawdopodobnie nie jest dobrym rozwiązaniem, ponieważ Django Admin nie wyświetli żadnego z Twoich specjalnych pól. Istnieją dwa powody tego:

  • UserAdmin używa UserChangeForm jako formy używanej przy modyfikowaniu obiektu, który z kolei używa User jako swojego modelu.
  • UserAdmin definiuje właściwość formsets, później używaną przez UserChangeForm, która nie zawiera specjalnych pól.

Więc, stworzyłem specjalny formularz zmiany, który przeciąża meta wewnętrzną klasę tak, że formularz zmiany używa właściwego modelu. Musiałem też przeciążać UserAdmin, aby dodać moje specjalne pola do zestawu pól, czyli część tego rozwiązania trochę mi się nie podoba, ponieważ wygląda trochę brzydko. Zachęcamy do sugerowania ulepszeń!

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)
 95
Author: nip3o,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-21 22:55:33

Odpowiedź Nico była niezwykle pomocna, ale okazało się, że Django nadal odwołuje się do modelu użytkownika podczas tworzenia nowego użytkownika.

Bilet #19353 odwołuje się do tego problemu.

Aby to naprawić musiałem zrobić kilka dodatkowych dodatków do 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)
 47
Author: kdh454,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-05 21:04:50

Prostsze rozwiązanie, 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 będzie poprawnie odwoływał się do modelu MyUser do tworzenia i modyfikacji. Używam Django 1.6.2.

 34
Author: cesc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 15:59:29

ODPOWIEDŹ Cesc nie działała dla mnie, gdy próbowałem dodać niestandardowe pole do formularza tworzenia. Może to się zmieniło od 1.6.2? Tak czy inaczej, zauważyłem, że dodanie pola do obu zestawów pól i add_fieldsets załatwiło sprawę.

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)
 1
Author: aidnani8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-15 20:38:56

Inne podobne rozwiązanie (wzięte stąd):

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
Author: Federico Comesaña,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-04 19:52:19