Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Custom User Model fields not appearing in Django admin

I'm trying to add some extra fields into the django.contrib.auth.models User model. I'll be using this custom User model throughout my project. I used AbstractUser to add name and contact fields.

class User(AbstractUser):
    name = models.CharField(_('Name of User'), blank=True, max_length=255)
    contact = models.CharField(max_length=20, blank=True)
    def __str__(self):
        return self.username

In my settings.py, I added to the apps.authentication, which is my app:

INSTALLED_APPS = [ 'apps.authentication', ...]

I also specified my AUTH_USER_MODEL:

AUTH_USER_MODEL = 'authentication.User'

I then ran migrations and it worked (I checked my local db; new tables were made). However, when I access it using the Django admin, the name and contact fields were nowhere to be found. How do I make the fields appear?

enter image description here

like image 683
Donovan Keating Avatar asked May 17 '18 16:05

Donovan Keating


3 Answers

You can append default UserAdmin class with custom fieldsets by adding following to admin.py file:

from django.contrib.auth.admin import UserAdmin

UserAdmin.fieldsets += ('Custom fields set', {'fields': ('name', 'contact')}),
like image 63
neverwalkaloner Avatar answered Oct 16 '22 17:10

neverwalkaloner


While the accepted solution does work, it puts all the new fields at the very bottom of the page. It's nice to be able to append fields to a specific section, and to move fields from one section to another.

I use these two utility functions for appending fields to a fieldset and moving fields from one fieldset to another:

common/utils/admin.py

def append_fields(fieldsets, section, fields):
    """
    fieldsets : tuple
        The fieldsets to append to.
            - fieldsets for editing existing objects
            - add_fieldsets for adding new objects
    section : str or None
        The title of the section. None for the titleless section.
    fields : tuple
        The fields being appended.
    """
    for fieldset in fieldsets:
        if fieldset[0] == section:
            fieldset[1]['fields'] += fields
            break 
    else: # Add new section
        fieldsets = fieldsets + (
            (section, {
                'classes': ('wide',),
                'fields': fields
            }),
        )
    return fieldsets

def move_field(fieldsets, field, from_section, to_section):
    """
    fieldsets : tuple
        The fieldsets to append to.
            - fieldsets for editing existing objects
            - add_fieldsets for adding new objects
    field: str
        The name of the field to move.
    from_section : str or None
        The title of the section from which to remove the field.
    to_section : str or None
        The title of the section in which to add the field.
    """
    for fieldset in fieldsets:
        if fieldset[0] == from_section:
            field_list = list(fieldset[1]['fields'])
            field_list.remove(field) # will raise exception if field not found
            fieldset[1]['fields'] = tuple(field_list)
            break
    else:
        raise Exception(f'No such from fieldset: {from_section}')

    for fieldset in fieldsets:
        print(fieldset)
        if fieldset[0] == to_section:
            fieldset[1]['fields'] = fieldset[1]['fields'] + (field, )
            break
    else:
        raise Exception(f'No such to fieldset: {to_section}')

Then I import it into my CustomUserAdmin class:

users/admin.py

from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

from common.utils.admin import append_fields, move_field

CustomUser = get_user_model()

class CustomUserAdmin(UserAdmin):
    model = CustomUser

    # Fields for editing existing user
    new_fields = ('dob', 'avatar')
    fieldsets = append_fields(UserAdmin.fieldsets, 'Personal info', new_fields)
    move_field(UserAdmin.fieldsets, 'email', 'Personal info', None)

    # Fields for adding new user
    new_fields = ('email', )
    optional_fields = ('first_name', 'last_name', 'dob')
    add_fieldsets = append_fields(UserAdmin.add_fieldsets, None, new_fields)
    add_fieldsets = append_fields(
        UserAdmin.add_fieldsets, 'Optional Fields', optional_fields
    )


admin.site.register(CustomUser, CustomUserAdmin)
like image 43
Webucator Avatar answered Oct 16 '22 15:10

Webucator


I think the part you are missing is registering your user model in the app’s admin.py:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

admin.site.register(User, UserAdmin)

(taken from https://docs.djangoproject.com/en/2.0/topics/auth/customizing/#specifying-a-custom-user-model)

like image 37
Rob Bricheno Avatar answered Oct 16 '22 17:10

Rob Bricheno