18

I am trying to redefine my admin page for the auth.User model. Everything is working properly, except for one thing. Check the code below:

from django.contrib import admin
from django.contrib.auth.models import User
from access.models import UserProfile


class UserProfileInline(admin.StackedInline):
    model = UserProfile

class UserAdmim(admin.ModelAdmin):
    inlines = [UserProfileInline,]
    list_display = ['id', 'username', 'get_full_name', 'email']


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

As you can see, one of the fields I want to be displayed in the model page listing -- defined by list_display -- is get_full_name. The problem is that the column label in the admin is displayed as Get full name.

My question is simple: can I override this? If so, how?

Thanks for your help.

K Z
  • 29,661
  • 8
  • 73
  • 78
Francisco
  • 1,352
  • 4
  • 13
  • 27
  • [Django admin listview Customize Column Name](https://stackoverflow.com/questions/9708455/django-admin-listview-customize-column-name) – s3m3dov Jun 07 '21 at 06:53

1 Answers1

53

Set an attribute in your function called short_description to your desired label in your model definition.

# note, this must be done in the class definition;
# not User.get_full_name.short_description
get_full_name.short_description = 'my label' 

Alternatively, if you don't want to pollute your model with admin specific code, you can set list_display to a method on the ModelAdmin which takes one argument: the instance. You'll also have to set readonly_fields so that the admin doesn't try to look up this field in your model. I prefix admin fields with _ to differentiate.

class MyAdmin(...):
    list_display = ('_my_field',)
    readonly_fields = ('_my_field', )     

    def _my_field(self, obj):
        return obj.get_full_name()
    _my_field.short_description = 'my custom label'


Update:

Note that this will break default admin ordering. Your admin will no longer sort fields by clicking the label. To enable this functionality again, define an admin_order_field.

def _date_created(self, obj):
    return obj.date_created.strftime('%m/%d/%Y')
_date_created.short_description = "Date Created"
_date_created.admin_order_field = 'date_created'

Update 2:

I've written an admin method decorator that simplifies this process, because once I started using highly descriptive verbose method names, setting attributes on the function became massively repetitive and cluttering.

def admin_method_attributes(**outer_kwargs):
    """ Wrap an admin method with passed arguments as attributes and values.
    DRY way of extremely common admin manipulation such as setting short_description, allow_tags, etc.
    """
    def method_decorator(func):
        for kw, arg in outer_kwargs.items():
            setattr(func, kw, arg)
        return func
    return method_decorator


# usage
class ModelAdmin(admin.ModelAdmin):
    @admin_method_attributes(short_description='Some Short Description', allow_tags=True)
    def my_admin_method(self, obj):
        return '''<em>obj.id</em>'''
Yuji 'Tomita' Tomita
  • 115,817
  • 29
  • 282
  • 245
  • Defining the short_description attribute did not work in the case of the auth.User model. Could you verify and maybe edit your answer? I got the following error: `AttributeError at /admin/auth/user/ 'instancemethod' object has no attribute 'short_description'. That's all I need to check this as the correct answer =) – Francisco Aug 21 '12 at 04:10
  • @Francisco, see I mentioned "in your model definition" - which in your case of `auth.User` you'd have to go into django source. Since that's not really an option, see the second part of my answer with the `_my_field`. – Yuji 'Tomita' Tomita Aug 21 '12 at 04:12
  • Django 3.2, instead of `allow_tags`, you should use: [`format_html`](https://docs.djangoproject.com/en/3.0/ref/utils/#django.utils.html.format_html) – caram Feb 23 '21 at 08:13