Add fields from another model to the admin site

1.6k Views Asked by At

My Profile model has a OneToOne relation with Django's built-in User model.

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    verified = models.BooleanField(default=False)

If I want to change user's password or properties like Active or Superuser I have to do it in one Change User page, and to edit verified property I have to go to another.

Is there any way to merge this:

enter image description here

And this:

enter image description here

Into one form so I can edit everything about a user in one page?

Edit 1:

As you guys suggested the StackedInline approach, let's see how it turns out.

Please first look at Django's default Admin site (first screenshot above):

  1. Everything is grouped in sections and sections have titles.
  2. Look at how the password information is displayed.
  3. There's a link to change the password.

Now I implement the StackedInline solution.

Please note that this is in the admin.py of my myapp:

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

# Register your models here.


class ProfileInline(admin.StackedInline):
    model = Profile

class UserAdmin(admin.ModelAdmin):
    inlines = (ProfileInline, )


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

Now let's look at Admin site:

enter image description here

  1. Everything is scattered. Sections and their titles are gone (Personal info, Permissions, etc).
  2. Password field shows the hashed password. All other information is gone.
  3. There's no link to change the password.

Edit 2:

To solve the problem of Edit 1 I look at the source code of Django (https://github.com/django/django/blob/main/django/contrib/auth/admin.py) and add update my code as below:

class UserAdmin(admin.ModelAdmin):
    inlines = (ProfileInline, )
    fieldsets = (
        (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")}),
    )
    add_fieldsets = (
        (
            None,
            {
                "classes": ("wide",),
                "fields": ("username", "password1", "password2"),
            },
        ),
    )

    filter_horizontal = (
        "groups",
        "user_permissions",
    )
    
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Now I have two sections in the Admin site:

The section on the top shows almost everything (except that the password field is still different and there's no link to change the password and also the verified field is not there) but sections and titles are back.

Then there's this additional and completely unnecessary part:

enter image description here enter image description here

As you can see:

  1. All fields of information about the user is repeated
  2. Look at the password field
  3. Information is not grouped in sections with titles
  4. verified filed appears.
3

There are 3 best solutions below

4
Gonçalo Peres On BEST ANSWER

OP can use one of the InlineModelAdmin objects such as StackedInline. This allows one to create inline forms providing one the ability to edit models on the same page as a parent model.

Adapting for OP's case, it would be something like

from django.contrib import admin

class ProfileInline(admin.StackedInline):
    model = Profile

class UserAdmin(admin.ModelAdmin):
    inlines = [
        ProfileInline,
    ]

admin.site.register(User, UserAdmin)

Now OP's admin site is set up to edit Profile objects inline from the User detail page.

2
Ahmad Akel Omar On

you can use override AbstractUser from model Django so you can merge user in one place like this:


from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
   verified = models.BooleanField(default=False)

and you need to add this line to Django settings.py file so that Django knows to use the new User class:


AUTH_USER_MODEL = 'users.CustomUser'

then make sure to migrate :


(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
1
Maxim Danilov On

User model Extension vs Inheritance.

Your profile model only add some elements to user. In this case Model inheritance can be better.

# models.py
class Profile(user):
    verified = models.BooleanField(default=False)

after that you can achieve all fields for user and for profile:

# admin.py
class ProfileAdmin(ModelAdmin):
    fields = '__all__'

if you don't want to switch on Model inheritance.

You can use InlineModel in UserAdmin to change related model.

# admin.py
class ProfileInline(StackedInline):
    model=Profile

class UserAdmin(ModelAdmin):
    inlines = (ProfileInline, )