Django auth UserAdmin gebruiken voor een aangepast gebruikersmodel

Van de Django.Contrib .Auth docs:

Django’s standaardgebruiker uitbreiden
Als u helemaal tevreden bent met het gebruikersmodel van Django en u wilt gewoon wat extra profielinformatie toevoegen, dan kunt u eenvoudig django.contrib.auth.models.AbstractUsersubclasseren en uw aangepaste profielvelden toevoegen. Deze klasse biedt de volledige implementatie van de standaardgebruiker als een abstract model.

Gezegd en gedaan. Ik heb een nieuw model gemaakt zoals hieronder:

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

Dit verschijnt in admin bijna zoals Django’s standaard User. Het belangrijkste verschil in admin is echter dat het wachtwoord-(re)set-veld niet aanwezig is, maar in plaats daarvan een normaal CharField wordt weergegeven. Moet ik echt dingen in de admin-config overschrijven om dit te laten werken? Zo ja, hoe kan ik dat dan op een enigszins DROGE manier doen (d.w.z. zonder dingen uit de Django-bron te kopiëren… eww…)?


Antwoord 1, autoriteit 100%

Na een tijdje in de Django-broncode te hebben gezocht, vond ik een werkende oplossing. Ik ben niet helemaal tevreden met deze oplossing, maar het lijkt te werken. Voel je vrij om betere oplossingen voor te stellen!


Django gebruikt UserAdminom de mooie admin-look voor het User-model weer te geven. Door dit gewoon in ons admin.py-bestand te gebruiken, kunnen we hetzelfde uiterlijk krijgen voor ons model.

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

Dit alleen is echter waarschijnlijk geen goede oplossing, aangezien Django Admin geen van uw speciale velden zal weergeven. Hier zijn twee redenen voor:

  • UserAdmingebruikt UserChangeFormals het formulier dat moet worden gebruikt bij het wijzigen van het object, dat op zijn beurt Userals model gebruikt.
  • UserAdmindefinieert een formsets-eigenschap, later gebruikt door UserChangeForm, die uw speciale velden niet bevat.

Dus ik heb een speciaal wijzigingsformulier gemaakt dat de Meta-binnenklasse overbelast, zodat het wijzigingsformulier het juiste model gebruikt. Ik moest ook UserAdminoverbelasten om mijn speciale velden aan de veldenset toe te voegen, wat het deel van deze oplossing is dat ik een beetje niet leuk vind, omdat het er een beetje lelijk uitziet. Voel je vrij om verbeteringen voor te stellen!

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)

Antwoord 2, autoriteit 41%

Een eenvoudigere oplossing, 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 zal correct verwijzen naar het MyUser-model voor creatie en wijziging.
Ik gebruik Django 1.6.2.


Antwoord 3, autoriteit 40%

Nico’s antwoord was buitengewoon nuttig, maar ik ontdekte dat Django nog steeds verwijst naar het gebruikersmodel bij het maken van een nieuwe gebruiker.

Ticket #19353verwijst naar dit probleem.

Om het te repareren moest ik nog een paar toevoegingen maken aan 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)

Antwoord 4, autoriteit 8%

cesc’s antwoord werkte niet voor mij toen ik probeerde een aangepast veld toe te voegen aan het aanmaakformulier. Misschien is het veranderd sinds 1.6.2? Hoe dan ook, ik vond het toevoegen van het veld aan beide veldensets en add_fieldsets deed de truc.

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)

Antwoord 5, autoriteit 2%

Een andere vergelijkbare oplossing (Vanaf hier genomen):

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)

Other episodes