23

If you want to store extra information about a user (django.contrib.auth.models.User) in Django you can use the nifty AUTH_PROFILE_MODULE to plug in a "profile" model. Each user then gets a profile. It's all described here:

Now, let's say I have created an application called accounts with a model called UserProfile and registered it as the profile model for my users. How do I inline the editing of the profile in the admin interface for editing users (or vice versa)?

André Laszlo
  • 15,169
  • 3
  • 63
  • 81
  • 2
    Just a note for new readers, `AUTH_PROFILE_MODULE` was deprecated around 8 years ago: https://code.djangoproject.com/ticket/15937 – Raunaqss Feb 19 '21 at 15:40

4 Answers4

33

I propse a slightly improved version of André's solution as it breaks the list view in /admin/auth/user/:

from django.contrib import admin
from member.models import UserProfile
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin

class UserProfileInline(admin.StackedInline):
 model = UserProfile
 max_num = 1
 can_delete = False

class UserAdmin(AuthUserAdmin):
 inlines = [UserProfileInline]

# unregister old user admin
admin.site.unregister(User)
# register new user admin
admin.site.register(User, UserAdmin)
Robert Lacroix
  • 439
  • 1
  • 4
  • 3
17

I propose another improvement to Robert's solution:

from django.contrib import admin
from member.models import UserProfile
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin

class UserProfileInline(admin.StackedInline):
   model = UserProfile
   max_num = 1
   can_delete = False

class UserAdmin(AuthUserAdmin):
   def add_view(self, *args, **kwargs):
      self.inlines = []
      return super(UserAdmin, self).add_view(*args, **kwargs)

   def change_view(self, *args, **kwargs):
      self.inlines = [UserProfileInline]
      return super(UserAdmin, self).change_view(*args, **kwargs)

# unregister old user admin
admin.site.unregister(User)
# register new user admin
admin.site.register(User, UserAdmin)

Without this change to UserAdmin, the custom UserProfileInline section will show up on the "add user" screen, which is just supposed to ask for the username and password. And if you change any of the profile data on that screen (away from the defaults) before you save, you'll get a "duplicate key" database error.

abjennings
  • 2,663
  • 3
  • 22
  • 22
  • Completely resolved my problem here: http://stackoverflow.com/questions/20214362/post-save-user-signal-that-creates-user-profile-is-being-called-twice-causing-du Thank you! You'd think this User/UserProfile admin setup would be part of the django documentation. – chewynougat Nov 26 '13 at 15:11
  • Thanks a lot! Finally I get this to behave as it should haha – Felix D. Oct 04 '15 at 04:22
17

Well, it turns out that this is quite easy, once you know how to do it. This is my myapp/accounts/admin.py:

from django.contrib import admin
from myapp.accounts.models import UserProfile
from django.contrib.auth.models import User

class UserProfileInline(admin.StackedInline):
    model = UserProfile
    max_num = 1
    can_delete = False

class AccountsUserAdmin(admin.UserAdmin):
    inlines = [UserProfileInline]

# unregister old user admin
admin.site.unregister(User)
# register new user admin that includes a UserProfile
admin.site.register(User, AccountsUserAdmin)

The default admin.UserAdmin ModelAdmin class for users is unregistered and a new one specifying an inline UserProfile is registered in its place. Just thought I should share.

Daniel Sokolowski
  • 11,982
  • 4
  • 69
  • 55
André Laszlo
  • 15,169
  • 3
  • 63
  • 81
  • 1
    How are you handling the password form link? Just these changes breaks it since it was only meant to be seen from the change form after a user with a name and password is added. – JivanAmara Jan 17 '11 at 06:13
  • 2
    The above is almost correct, the proper way which also does the 'password form link' is to extend the custom `UserAdmin` as opposed using `admin.ModelAdmin` - try: `from django.contrib.auth.admin import UserAdmin` then `class UserProfileAdmin(UserAdmin):` – Daniel Sokolowski Mar 14 '13 at 18:04
0

You have to consider the add and change form. OTherwise you will get a user cannot be None error when trying to create a user. The following has been tested and works in 1.3:

class TeamInline(admin.StackedInline):
  model = Team
  fk_name = 'user'
  max_num = 1
  can_delete = False

class TeamUserAdmin(UserAdmin):
  list_display = ('username', 'email', 'company', 'expertise', 'contact_email', 'contact_phone', 'twitter', 'facebook', 'last_login_short', 'options')
  list_select_related = True

  def add_view(self, *args, **kwargs):
    self.inline_instances = []
    return super(TeamUserAdmin, self).add_view(*args, **kwargs)

  def change_view(self, *args, **kwargs):
    self.inline_instances.append(TeamInline(self.model, self.admin_site))
    return super(TeamUserAdmin, self).change_view(*args, **kwargs)
Paul Kenjora
  • 1,914
  • 18
  • 20