Django 1.11 or 1.8 Admin App/Model Reordering

Django apps are registered via installed_apps in settings and models are registered via admin.py. And once registered they show up alphabetically on the admin panel. To reorder them we have to either tinker with the admin html files or add template tags. Here is a middleware that avoids all of that and helps you label admin apps, models and also order them the way you want.

Steps to follow:

Let us assume the following django directory structure:

myproject/
    manage.py
    myproject/
        __init__.py
        urls.py
        wsgi.py
        settings/
            __init__.py
            base.py
            dev.py
            prod.py
    myapp1/
        __init__.py
        models.py
        views.py
        urls.py
        templates/
           …
        static/
           …
        tests/
    myapp2/
        __init__.py
        models.py
        views.py
        urls.py
        templates/
           …
        static/
            …
        tests/

 

1- Create a mymiddleware.py file within any of you apps (say myapp1)

2- Add the following content to the mymiddleware.py file

from copy import deepcopy
from django.conf import settings
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import resolve
'''
For Django 1.11 use this init function and class instead
from django.utils.deprecation import MiddlewareMixin
class AdminReorder(MiddlewareMixin):
    def __init__(self, get_response):
        self.get_response = get_response
'''
class AdminReorder(object):

    def init_config(self, request, app_list):
        self.request = request
        self.app_list = app_list

        self.config = getattr(settings, 'ADMIN_REORDER', None)
        if not self.config:
            # ADMIN_REORDER settings is not defined.
            raise ImproperlyConfigured('ADMIN_REORDER config is not defined.')

        if not isinstance(self.config, (tuple, list)):
            raise ImproperlyConfigured(
                'ADMIN_REORDER config parameter must be tuple or list. '
                'Got {config}'.format(config=self.config))

        admin_index = admin.site.index(request)
        try:
            # try to get all installed models
            app_list = admin_index.context_data['app_list']
        except KeyError:
            # use app_list from context if this fails
            pass

        # Flatten all models from apps
        self.models_list = []
        for app in app_list:
            for model in app['models']:
                model['model_name'] = self.get_model_name(
                    app['app_label'], model['object_name'])
                self.models_list.append(model)

    def get_app_list(self):
        ordered_app_list = []
        for app_config in self.config:
            app = self.make_app(app_config)
            if app:
                ordered_app_list.append(app)
        return ordered_app_list

    def make_app(self, app_config):
        if not isinstance(app_config, (dict, str)):
            raise TypeError('ADMIN_REORDER list item must be '
                            'dict or string. Got %s' % repr(app_config))

        if isinstance(app_config, str):
            # Keep original label and models
            return self.find_app(app_config)
        else:
            return self.process_app(app_config)

    def find_app(self, app_label):
        for app in self.app_list:
            if app['app_label'] == app_label:
                return app

    def get_model_name(self, app_name, model_name):
        if '.' not in model_name:
            model_name = '%s.%s' % (app_name, model_name)
        return model_name

    def process_app(self, app_config):
        if 'app' not in app_config:
            raise NameError('ADMIN_REORDER list item must define '
                            'a "app" name. Got %s' % repr(app_config))

        app = self.find_app(app_config['app'])
        if app:
            app = deepcopy(app)
            # Rename app
            if 'label' in app_config:
                app['name'] = app_config['label']

            # Process app models
            if 'models' in app_config:
                models_config = app_config.get('models')
                models = self.process_models(models_config)
                if models:
                    app['models'] = models
            return app

    def process_models(self, models_config):
        if not isinstance(models_config, (dict, list, tuple)):
            raise TypeError("models" config for ADMIN_REORDER list '
                            'item must be dict or list/tuple. '
                            'Got %s' % repr(models_config))

        ordered_models_list = []
        for model_config in models_config:
            model = None
            if isinstance(model_config, dict):
                model = self.process_model(model_config)
            else:
                model = self.find_model(model_config)

            if model:
                ordered_models_list.append(model)

        return ordered_models_list

    def find_model(self, model_name):
        for model in self.models_list:
            if model['model_name'] == model_name:
                return model

    def process_model(self, model_config):
        # Process model defined as { model: 'model', 'label': 'label' }
        for key in ('model', 'label', ):
            if key not in model_config:
                return
        model = self.find_model(model_config['model'])
        if model:
            model['name'] = model_config['label']
            return model

    def process_template_response(self, request, response):
        url = resolve(request.path)
        if not url.app_name == 'admin' and \
                url.url_name not in ['index', 'app_list']:
            # current view is not a django admin index
            # or app_list view, bail out!
            return response

        try:
            app_list = response.context_data['app_list']
        except KeyError:
            # there is no app_list! nothing to reorder
            return response

        self.init_config(request, app_list)
        ordered_app_list = self.get_app_list()
        response.context_data['app_list'] = ordered_app_list
        return response

3- Next add the following to the myproject/settings/base.py

MIDDLEWARE_CLASSES = (
…
'myapp1.mymiddleware.AdminReorder',
)

3- Now lets reorder and rename your models and apps.

Let say within myapp1 we have 3 models myapp1model1, myapp1model2, myapp1model3 and within myapp2 we have 2 models myapp2model1, myapp2model2

So within base.py again lets add this:

ADMIN_REORDER = (
{'app': 'myapp1', 'label': 'My Application 1',
'models': ({'model':"myapp1.myapp1model3",'label':'My App1 Model3'},
{'model':"myapp1.myapp1model2",'label': 'MyModel2'},
myapp1.myapp1model1)},
{'app': 'myapp2', 'label': 'My Application 2',
'models': ("myapp2.myapp2model2", "myapp2.myapp2model1")
)

So that will reorder you apps. Hope that helps!

Advertisements

2 thoughts on “Django 1.11 or 1.8 Admin App/Model Reordering

  1. thanks your posting. But i have error at line 83 of above middleware at line ‘models_config = app_config.get(‘models’=self.process_models(models_config))’
    Please fix it

Leave a Reply to Pragnya Dash Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s