Django under the hood: how the Django admin works - Ola Sitarska

Tags: django, djangocon

(One of my summaries of a talk at the 2015 django under the hood conference).

Ola Sitarska gave a higher-level talk about the django admin at the recent Cardiff djangocon. She loves the django admin.

The django admin hasn’t seen any big updates for the last 8 years. It just works and it works well and it is stable. Until django 1.9: there’s a new visual skin for the admin. Check it out! (She showed a screenshot later on in the presentation: yes, it looks great!)

There are three main parts to the django admin: AdminSite, ModelAdmin, ChangeList.

  • The AdminSite encapsulates an instance of the django admin application.

    You don’t need to do admin.autodiscover() anymore as it is called automatically by Django now that django has a signal for when an app is loaded. For the admin app, it fires off autodiscover().

    Autodiscover finds all your models and extracts information about them. Including the admin.py customization/configuration. This ends up as a list of admin URLs.

    Note: you can have multiple admins with different configurations in case you have a need for two completely differently configured admin sites.

    Some of the things you can customize on an adminsite are the site_title and site_header, login_form, index_template etc.

    If you want to change something globally in your admin, the AdminSite is probably the place to do it.

  • The ModelAdmin contains all the admin options and functionality for any given model.

    The AdminSite autodiscover looks at the admin.py files. There you can configure the ModelAdmin for your models. There are a lot of options you can tweak.

    A modeladmin can have a custom get_urls() method. In this way you can customize or even add pages to your admin for the model. Normally you have a add_view, change_view, etc. You can also pass in different form templates.

    You can hook into the permission machinery with methods like has_change_permission(self, request, obj=None).

    But… all those hooks and especially the form handling for the change form makes things hard. You might be better off writing your own view.

    A good way to customize a model admin is to pass in a custom form or add_form.

    A gotcha: a modeladmin is initialized when django starts up, not for every request. So watch out with saving things on self.

    Handy: raw_id_fields when there are a lot of items your foreignkey can point at. Rendering the admin page can take a long time, then. Raw id fiels only contain the primary key and a handy search box.

  • The Changelist is the overview page that lists the objects available of your model.

    It is an internal component that makes sure your actions and filters are always up to date. It does a good job. But there is no documentation for it. There is no API. There are lots of things you can customize, though.

    Some of the things it does: what are the filters? What is searched? Order? Pagination? Pagination params in the query string? Etc.

    Filters are handy. Normally you just pass in the name of a field. But you can also pass in a filter class. BooleanListFilter(), for instance. DecadeBornListFilter. And you can write your own! An example:

    class RelevantPortalFilter(admin.SimpleListFilter):
        title = _('portal')
        parameter_name = 'portal__id__exact'
    
        def lookups(self, request, model_admin):
            return models.Portal.objects.filter(
                roles__isnull=False).distinct().values_list(
                'id', 'name')
    
        def queryset(self, request, queryset):
            if not self.value():
                return queryset
            return queryset.filter(portal=self.value())
    

    (Note by Reinout: I copied that code from some code I recently wrote myself instead of typing over from the presentation)

    A customization point: get_queryset(), this should return the objects you want to show. get_results() actually calls get_queryset(). It might use get_paginator(). It looks at get_filters() and get_filters_params() that grab the filters and their GET parameters and checks them for validity.

    Those filters are then applied to the queryset. Afterwards the ordering is applied: get_ordering() in the admin. Then default ordering in the model. And it looks at ordering that might be applied by the user in the user interface.

    Next step: searching with get_search_results() if you’ve defined search_fields on which to do a textual search.

So: the admin can be customized a lot and it is a nice part of Django.

Former railway tunnel at Neuerburg

Image: cycling on former railways this summer. This is the railway tunnel at Neuerburg, Germany.

water-gerelateerd Python en Django in het hartje van Utrecht!
 
vanrees.org logo

Reinout van Rees

My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.

Weblog feeds

Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):