ti-enxame.com

Usando o Django auth UserAdmin para um modelo de usuário personalizado

Do Django.Contrib.Auth docs :

Estendendo o usuário padrão do Django Se você estiver totalmente satisfeito com o modelo de usuário do Django e quiser apenas adicionar mais informações de perfil, basta subclassificar Django.contrib.auth.models.AbstractUser e adicionar seus campos de perfil personalizados. Essa classe fornece a implementação completa do usuário padrão como um modelo abstrato.

Dito e feito. Eu criei um novo modelo como abaixo:

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

Isso aparece no admin quase como o User padrão do Django. No entanto, a diferença mais importante no admin é que o campo password (re) set não está presente, mas um CharField normal é exibido no lugar. Eu realmente tenho que substituir coisas no admin-config para fazer isso funcionar? Se sim, como posso fazer isso de alguma forma DRY (ou seja, sem copiar coisas da fonte do Django ... eww ...)?

65
nip3o

Depois de pesquisar o código-fonte do Django por algum tempo, encontrei uma alma funcional. Eu não estou totalmente feliz com esta solução, mas parece funcionar. Sinta-se à vontade para sugerir melhores soluções!


O Django usa UserAdmin para renderizar o visual Nice admin para o modelo User. Usando apenas isso em nosso arquivo admin.py-, podemos obter a mesma aparência para o nosso modelo.

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

No entanto, isso provavelmente não é uma boa solução, já que o Django Admin não exibirá nenhum de seus campos especiais. Há duas razões para isso:

  • UserAdmin usa UserChangeForm como o formulário a ser usado ao modificar o objeto, que por sua vez usa User como seu modelo.
  • UserAdmin define uma propriedade formsets-, posteriormente usada por UserChangeForm, que não inclui seus campos especiais.

Então, eu criei um formulário de mudança especial que sobrecarrega a classe interna Meta para que a forma de mudança use o modelo correto. Eu também tive que sobrecarregar o UserAdmin para adicionar meus campos especiais ao fieldset, que é a parte desta solução que eu não gosto um pouco, já que parece um pouco feio. Sinta-se à vontade para sugerir melhorias!

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)
103
nip3o

a resposta do nico tem sido extremamente útil, mas descobri que o Django ainda faz referência ao modelo User ao criar um novo usuário.

Ticket # 19353 referencia esse problema.

A fim de consertá-lo eu tive que fazer mais algumas adições ao 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)
50
kdh454

Uma solução mais simples, 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)

O Django irá referenciar corretamente o modelo MyUser para criação e modificação. Eu estou usando o Django 1.6.2.

38
cesc

a resposta de cesc não estava funcionando para mim quando tentei adicionar um campo personalizado ao formulário de criação. Talvez tenha mudado desde o 1.6.2? De qualquer forma, eu encontrei adicionando o campo a ambos os conjuntos de campos e add_fieldsets fez o truque. 

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)
3
aidnani8

Outra solução similar ( Levou daqui ):

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
Federico Comesaña