Reordering list of models in Django Admin

Wouldn’t it be great if sorting models in the Django Admin is just as easy as setting a priority number in your ModelAdmin subclass?

In my project, I made a BaseAdmin class that has an admin_priority property:

class BaseAdmin(admin.ModelAdmin):
    admin_priority = 20

This property can be overridden to a lesser number to boost a model upwards the list of models in the Django Admin site, or a greater number to push it downwards.

To make this work, I replaced the default admin.AdminSite.get_app_list with this:

def get_app_list(self, request):
    app_dict = self._build_app_dict(request)
    from django.contrib.admin.sites import site
    for app_name in app_dict.keys():
        app = app_dict[app_name]
        model_priority = {
            model['object_name']: getattr(
                site._registry[apps.get_model(app_name, model['object_name'])],
                'admin_priority',
                20
            )
            for model in app['models']
        }
        app['models'].sort(key=lambda x: model_priority[x['object_name']])
        yield app

admin.AdminSite.get_app_list = get_app_list

I wish to add this to Django itself. Is it better to contribute to the repo itself or just create my own plugin?

3 Likes

Hi @clrke

This is a nice approach and not too much code - goo d work. I’ve seen a different approach setting the Meta.verbose_name attribute for all models to include a prefix to force sorting, and yours is definitely a nicer.

That said - this is a pretty small amount of code to implement it on a new project. Merging a new feature like this to Django means it needs tests, documentation, and maintenance from now until forever, so we’re always cautious about adding new things. It might be better if you release this as a third party package, or share the code in a blog post, and if you can show that it’s popular then it’d be more worth consideration of merging.

Thanks,

Adam

Thanks for the compliment and advice, @adamchainz!

I’ll write a blog post about this soon.

1 Like

@clrke : Cool, can you please tell me where you placed the BaseAdmin class? Thx!

Hi @clrke,

Where do I need to place this code ?

1 Like

Apparently, there was a constant setting called ‘admin_reorder’ way back in 2012 (version 1.4 or thereabouts). SEE djangosnippets: Admin App/Model Custom Ordering. I’ve even seen people recently talk about an ‘ADMIN_ORDERING’ constant that can be put in settings, but there is no such setting in the base settings file. SEE Settings | Django documentation | Django. So there seems to have been both interest in the community and capacity among the core devs to have this solution available. Can you find out why it was removed? Or maybe it is still there but now undocumented? It would certainly be preferable to having people hack the core code, as some others have suggested. Nor would it leave people like loctimize and Nasir on this thread hanging with incomplete instructions as to where to put this code - a flaw that is also in the 3rd party book on this subject. Users need good, up to date, complete, and understandable guidance as to this and everything else with Django. My 2 cents. Thanks for responding.

I did some digging in Django’s bug tracker (searching for closed tickets related to the admin whose description contains the word “order”) and found ticket 7497.

With a ticket this old, I suspect there’s either some hidden complexity or a lack on consensus on how to move forward.

Just wondering about this answer. How about no sorting at all? That would be much easier to maintain, forever, and would let users choose the order in which models show up in the admin panel?

Here is my version:

def get_app_list(self, request, app_label=None):
    # Return the installed apps that have been registered
    # in this site in the order the user has registred them
    app_dict = self._build_app_dict(request, app_label)
    app_list = app_dict.values()

    # Do not sort models alphatbetically
    # As the Boss said - Take 'em as they come
    #for app in app_list:
    #    app["models"].sort(key=lambda x: x["name"])

    return app_list

admin.AdminSite.get_app_list = get_app_list

@clrke - excellent contribution!

1 Like

@unsinkable2 your code is great for models, but for me it results in error when clicking on the app name.
So I wrapped the app_list in a list (because it was a mapping before.

def get_app_list(self, request, app_label=None):
    """Return the installed apps that have been registered in admin.py"""
    app_dict = self._build_app_dict(request, app_label)
    app_list = list(app_dict.values())
    return app_list
2 Likes

Nice catch - thanks for posting the updated version!