There are several ways to extend the the default Django User model. Perhaps one of the most common way (and also less intrusive) is to extend the User model using a one-to-one link. This strategy is also known as User Profile. One of the challenges of this particular strategy, if you are using Django Admin, is how to display the profile data in the User edit page. And that’s what this tutorial is about.
I’ve published a while ago an article about How to Extend Django User Model, describing in great detail all the different strategies. If you are still not familiar with it, I strongly suggest that you have a look in this article.
This tutorial is about the User Profile strategy. So, consider we have an app named core with the following model definition:
What we want to achieve is making the fields location, birthdate and role available to be edited on Django Admin.
Editing The User Profile
The trick is very simple. We will extend the default
UserAdmin, add the profile instance as an inline and switch
UserAdmin Django uses.
A few things here: I intentionally defined the verbose_name_plural as Profile, because each user can have only
one profile, and as the component we are using is an
StackedInline (which normally is used for formsets), just to
avoid displaying Profiles in plural when we only have one profile. It’s just a minor thing.
Then a very important thing, we need to override the
get_inline_instances method, so to display the inlines only
in the edit form. Otherwise we might get some problems because of how the Signals work. Remember that the Signal is
responsible for creating the Profile instance.
Since by default Django only provides username and password upon user creation, this way we keep the default behavior.
Finally we unregister the old User admin and register the new one, the custom with the Profile model.
It will look like this:
Cool, right? It just works.
Adding Profile Fields to List View
Now what if we want to display the User location (which is defined inside the profile model), in the list view, like this:
Since we are already extending the
UserAdmin, it’s just a matter of overriding the
We have to define an extra method,
get_location and append it to the
list_display, because the field is defined in
a external model (the relationship is defined in the Profile model, not in the User model). So for the Django Admin
understand how to display the location attribute, we have to play it this way.
get_location.short_description is just to display it prettier in the table header. Otherwise Django Admin would
display it as “Get Location” (which is the name of the method).
A very important detail: note the
list_select_related. We are adding the profile relationship there, so to avoid
firing hundreds of unnecessary queries in the database. For more on that subject, check this post:
Django Tips #3 Optimize Database Queries.
That’s it! Plain simple. This also open an opportunity to explore more the User model in Django Admin. You can override several attributes and very easily add new list actions for example.
Django’s documentation is awesome. But even better is to explore its the source code. For example, to understand more
on the definitions of the
UserAdmin, don’t be afraid to explore the source code and see the class’ attributes and
Also the source code I used in this tutorial is available on GitHub: sibtc/django-admin-user-profile.