19

I'm trying to understand the django admin better and at the same time, I'm trying to add one more field to the current user admin. In models.py I've done

User.add_to_class('new_field', models.BooleanField(default=False)) 

and in admin.py I've got the following (with fieldsets basically just copied from django/contrib/auth/admin.py)

class AdjUserAdmin(UserAdmin): list_display = UserAdmin.list_display + ('new_field',) list_filter = UserAdmin.list_filter + ('new_field',) fieldsets = UserAdmin.fieldsets fieldsets[1][1]['fields'] = ('first_name','last_name','email','new_field') 

The problem is, when I do this I get the error:

AdjUserAdmin.fieldsets[4][1]['fields']' refers to field 'new_field' that is missing from the form.

I've looked at UserChangeForm, but it looks like it's already correctly pulling in User as the model. I'm not sure as to why new_field is missing from the form.

Thanks

In regards to this being smelly code

I know this is a smelly monkey patching way to go about doing this, but subclassing gives me issues mainly for these reasons.. if I could get it to work the way stated above, I'd be happy.. and maybe smelly.

In regards to the recommended way

I'm aware of the recommended way of creating a user profile, just that in particular situations, I don't see the merit in creating an entire new table and having an additional call to the database when all I want to store is an extra bit of information such as is_private or some such. If I'm storing lots more info, then I agree, setting up a user profile is preferable.

8 Answers 8

32

First the "is it plugged in?" question -- Have you manually added new_field to the users table in the database? Syncdb wouldn't have taken care of that, of course.

After that, I would try appending the fields onto the existing UserAdmin rather than rebuilding it from scratch:

from django.contrib.auth.admin import UserAdmin UserAdmin.list_display += ('new_field',) # don't forget the commas UserAdmin.list_filter += ('new_field',) UserAdmin.fieldsets += ('new_field',) 
Sign up to request clarification or add additional context in comments.

3 Comments

Hmm.. dunno why I didnt think of that after using list_display = UserAdmin.list_display + ('new_field',).. thanks!
When i use: UserAdmin.list_display += ('nickname',) UserAdmin.list_filter += ('nickname',) UserAdmin.fieldsets += ('nickname',) <-----> there is something wrong, like this:<class 'django.contrib.auth.admin.UserAdmin'>: (admin.E008) The value of 'fieldsets[4]' must be a list or tuple. <-----> and i chang to : UserAdmin.list_display += ('nickname',) UserAdmin.list_filter += ('nickname',) UserAdmin.fieldsets += (('nickname', {'fields': ('nickname',)}),) <-----> this problem is gone.
@bovenson You can do it this way UserAdmin.fieldsets += (('Extra Fields', {'fields': ('new_field', )}),)
6

Just figured this out, perhaps this could help you as well.

Since you don't mention that you have a separate profile, if you want to simply add a column to the existing User admin, you can do the following in admin.py:

First you create a custom admin by subclassing UserAdmin:

class CustomUserAdmin(UserAdmin): list_display = UserAdmin.list_display + ('is_complete',) def is_complete(self, obj): # Example here, you can use any expression. return SomeOtherClass.objects.get(my_field=obj).is_complete() # Not required, but this gives you a nice boolean field: is_complete.boolean = True 

Then unregister the existing UserAdmin and register your own:

admin.site.unregister(User) admin.site.register(User, CustomUserAdmin) 

Comments

4

It is preferred to write your own user profile class, and attach it to the User model. Then you can use the get_profile() method to retrieve the profile from the user.

Subclassing the profile admin from an Inline Admin should also allow you to edit the profile on the user's page, which is almost what you're trying to do.

This post has a really good write-up on the issue: http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/

Comments

3

Based on @anschauung response, what worked for me in Django 3.2 is:

from django.contrib.auth.admin import UserAdmin # don't forget the commas UserAdmin.list_filter += ('new_field',) UserAdmin.fieldsets += (('Extra Fields', {'fields': ('new_field', )}),) 

Comments

2

Despite your DB look up concerns for having a UserProfile, that is really the way you should go for this problem. There are two main reasons for this:

  1. The User Model is pretty tightly coupled to Django's authentication system and to many other plugins. Monkey patching it isn't a good idea.

  2. Django has built-in support for creating User Profiles and many extensions know how to play nicely with these. By using User Profiles (see http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users for the main discussion on this) you can benefit from that.

If you're looking to add functionality to the Admin interface for users, then this note may be helpful:

http://www.thenestedfloat.com/articles/displaying-custom-user-profile-fields-in-djangos-admin/index.html

Regards,

Ian

Comments

1

Answer for Django 5

fieldsets is a tuple of tuples and looks like so:

( (None, {'fields': ('username', 'password')}), ('Personal info', {'fields': ('first_name', 'last_name', 'email')}), ('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}), ('Important dates', {'fields': ('last_login', 'date_joined')}), ) 

Therefore, need to add tuple with a new name:

from django.contrib.auth.admin import UserAdmin as DefaultUserAdmin from users.models import User @admin.register(User) class UserAdmin(DefaultUserAdmin): list_display = ["id", "username", "email", "first_name", "last_name"] ... fieldsets = DefaultUserAdmin.fieldsets + (("Custom", {"fields": ("avatar",)}),) 

Comments

-1

I got the 'that is missing from the form' error, and discovered that it was due to my field being marked as 'editable=False' in the model.

Comments

-1

For Django 4.2

Modify your_apps/models.py

In here, Create custom user model inherited by AbstractUser.
Create new field you want.

 from django.db import models from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): {new_field} = models.BooleanField(default=False) pass 

Modify your_apps/admin.py

from django.contrib import admin from django.contrib.auth.models import User from django.contrib.auth.admin import UserAdmin from .models import CustomUser class CustomUserAdmin(UserAdmin): list_display = ["id", "username", "email", "first_name", "last_name", "{new_field}", ] fieldsets = UserAdmin.fieldsets fieldsets[2][1]['fields'] += ("{new_field}",) # I designated permission fields for an example. admin.site.unregister(User) admin.site.register(CustomUser, CustomUserAdmin) 

Modify settings.py

AUTH_USER_MODEL = "{your_apps.CustomUser}" INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", ... "{your_apps}", ] 

Make migrations, and migrate

Done !

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.