89 votes

Utilisation de Django auth UserAdmin pour un modèle d'utilisateur personnalisé

De la Docs Django.Contrib.Auth :

Extension de l'utilisateur par défaut de Django Si le modèle User de Django vous convient parfaitement et que vous souhaitez simplement ajouter des informations de profil supplémentaires, vous pouvez simplement sous-classer django.contrib.auth.models.AbstractUser et ajoutez vos champs de profil personnalisés. Cette classe fournit l'implémentation complète de l'utilisateur par défaut en tant que modèle abstrait.

C'est dit et fait. J'ai créé un nouveau modèle comme ci-dessous :

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

Cela s'affiche dans l'administration presque comme le standard de Django User . Cependant, la différence la plus importante dans l'administration est que le champ de (re)définition du mot de passe n'est pas présent, mais un CharField normal est affiché à la place. Dois-je vraiment remplacer des éléments de la configuration d'administration pour que cela fonctionne ? Si c'est le cas, comment puis-je le faire d'une manière un peu DRY (c'est-à-dire sans copier des choses depuis les sources de Django... eww...) ?

143voto

nico Points 837

Après avoir fouillé dans le code source de Django pendant un certain temps, j'ai trouvé une solution qui fonctionne. Je ne suis pas totalement satisfait de cette solution, mais elle semble fonctionner. N'hésitez pas à suggérer de meilleures solutions !


Django utilise UserAdmin pour rendre le regard de l'admin sympa pour User modèle. En utilisant simplement ceci dans notre admin.py -nous pouvons obtenir le même aspect pour notre modèle.

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

Toutefois, cette solution seule n'est probablement pas la bonne, car Django Admin n'affichera aucun de vos champs spéciaux. Il y a deux raisons à cela :

  • UserAdmin utilise UserChangeForm comme forme à utiliser lors de la modification de l'objet, qui utilise à son tour User comme son modèle.
  • UserAdmin définit un formsets -qui sera utilisé plus tard par UserChangeForm qui n'inclut pas vos champs spéciaux.

J'ai donc créé un formulaire de modification spécial qui surcharge la classe interne Meta afin que le formulaire de modification utilise le bon modèle. J'ai également dû surcharger UserAdmin pour ajouter mes champs spéciaux à l'ensemble de champs, ce qui est la partie de cette solution qui me déplaît un peu, car elle est un peu moche. N'hésitez pas à suggérer des améliorations !

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)

59voto

cesc Points 21

Une solution plus simple, 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 fera correctement référence au modèle MyUser pour la création et la modification. J'utilise Django 1.6.2.

57voto

kdh454 Points 313

La réponse de nico a été extrêmement utile mais j'ai constaté que Django fait toujours référence au modèle User lors de la création d'un nouvel utilisateur.

Ticket #19353 fait référence à ce problème.

Afin de le corriger, j'ai dû faire quelques ajouts supplémentaires à 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)

12voto

aidnani8 Points 1032

La réponse de cesc ne fonctionnait pas pour moi lorsque j'ai essayé d'ajouter un champ personnalisé au formulaire de création. Peut-être cela a-t-il changé depuis la version 1.6.2 ? Quoi qu'il en soit, j'ai trouvé que l'ajout du champ à la fois à fieldsets et à add_fieldsets faisait l'affaire.

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)

3voto

Une autre solution similaire ( Pris d'ici ) :

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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X