Using ChangeList in views

The ChangeList provided in Django admin is so powerful and useful. We used it in our views and were surprised at the things we can do. It was like exposing the admin change-list page to everyone, in a secure way. Adding new features or updating the display is now just a 1-2 line change in list_display and list_filter options.

Proof of Concept

We create a function to create a ChangeList object from any queryset. It doesn’t need to be a model instance. Full code is here →.

We use the function like this:

queryset = Book.objects.filter(available=True)

cl = get_change_list(
    title="Books available",
    request=request,
    queryset=queryset,
    list_display=("title", "author", "price"),
    list_filter=("author", "price", DeliveryFilter),
    # we can define custom filters and displays just like we do in admin.py
)

context = {'cl': cl, 'opts': cl.opts}

This is how we use the above in templates:

{% load admin_list %}

<!-- render search -->
<div>{% search_form cl %}</div>

<!-- render date_hierarchy -->
{% if cl.date_hierarchy %}{% date_hierarchy cl %}{% endif %}

<!-- render results table -->
{% result_list cl %}

<!-- render pagination -->
{% pagination cl %}

<!-- render filters -->
{% if cl.has_filters %}
<div>
    {% if cl.has_active_filters %}
      <a href="{{ cl.clear_all_filters_qs }}">Clear all</a>
    {% endif %}

  <div>
    {% for spec in cl.filter_specs %}
      {% admin_list_filter cl spec %}
    {% endfor %}
  </div>
</div>
{% endif %}

All the above tags search_form, date_hierarchy, result_list, pagination and admin_list_filter are loaded from admin_list. We require zero code. We can still personalise everything using CSS. Just like we do with Django Forms.

Advantages
The above allows us to use these on any page.

  • A search
  • A date-hierarchy
  • Pagination
  • Filters
  • Customisable table

Larger ideas
I think we can re-factor the existing ChangeList module to make the above even easier. Just like Django forms.

The current ChangeList module is a bit coupled with models through ModelAdmin. It doesn’t need to be so. We can refactor it to handle any queryset. And that can allow us to use it at wider places.

Has anyone tried this? Does anyone else find this useful?

ChangeList is a Django admin internal and very strongly coupled to ModelAdmin. And as an undocumented internal, it can be changed arbitrarily between Django versions.

I don’t think Django should expose it for use outside of the admin. There has long been a policy to reject requests to make the admin more general purpose - it’s not your porject and should not be treated as such. But you’re free to take inspiration for it.

Some parts of what ChangeList does are available as general-purpose tools, such as Paginator for pagination, or django-filter for filtering.

1 Like

As a potential counterpoint - there has long been a desire to standardise how the admin works with the rest of Django. Perhaps pulling well-defined pieces out for general use in a way that can still be used by the admin would be the way forward to achieve that.

All that said, the admin is not my wheelhouse, so I’ll defer to the judgement of others.

2 Likes

I don’t have opinions on whether making ChangeList reusable is a worthwhile goal or not. Just want to flag the current implementation has a lot of basic accessibility issues, so in its current state I’d recommend avoiding it. Or if you do reuse it, be prepared to have to chance significant portions of the HTML to make it work.

We will obviously want to fix those issues regardless of whether the ChangeList is in Django admin only or not, but so far there’s been more pressing issues to address.