I have run into the case where I am managing the codebase for a project that utilizes the django-admin portion of a site. All of the functionality of the django admin exists in normal views as well, but for some reason the client prefers to work on the admin views as opposed to the function based views... Normally, adding in a dropdown and adjusting the pagination/filter would be easy in a function based view, but the only way I can see to modify this is with list_per_page
How do I add a dropdown to the admin page (preferably with the pagination buttons) and then how do I retrieve the results on the server side to alter the list_per_page
value dynamically based on what the user has selected? Would adding a form to the template and retrieving a POST in the admin work?
Inspired by plum-0 answer, I've ended up with this :
import django.contrib.admin.views.main
class DynPaginationChangeList(django.contrib.admin.views.main.ChangeList):
def __init__(self, request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by):
page_param = request.GET.get('list_per_page', None)
if page_param is not None:
# Override list_per_page if present in URL
# Need to be before super call to be applied on filters
list_per_page = int(page_param)
super(DynPaginationChangeList, self).__init__(request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by)
def get_filters_params(self, params=None):
"""
Return all params except IGNORED_PARAMS and 'list_per_page'
"""
lookup_params = super(DynPaginationChangeList, self).get_filters_params(params)
if 'list_per_page' in lookup_params:
del lookup_params['list_per_page']
return lookup_params
class AdminDynPaginationMixin:
def get_changelist(self, request, **kwargs):
return DynPaginationChangeList
If you use the javascript code propose in the original answer you just need to use this Mixin in your AdminClass and voilà.
I personally override the pagination.html template like this :
{% load admin_list %}
{% load i18n %}
<p class="paginator">
{% if pagination_required %}
{% for i in page_range %}
{% paginator_number cl i %}
{% endfor %}
{% endif %}
{{ cl.result_count }} {% if cl.result_count == 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endif %}
{% if show_all_url %}<a href="{{ show_all_url }}" class="showall">{% translate 'Show all' %}</a>{% endif %}
{% with '5 10 25 50 100 250 500 1000' as list %} — {% translate 'Number of items per page' %}
<select>
{% if cl.list_per_page|slugify not in list.split %}
<option selected>{{ cl.list_per_page }}</option>
{% endif %}
{% for i in list.split %}
<option value="{{ i }}" {% if cl.list_per_page|slugify == i %}selected{% else %}onclick="var p = new URLSearchParams(location.search);p.set('list_per_page', '{{ i }}');window.location.search = p.toString();"{% endif %}>{{ i }}</option>
{% endfor %}
</select>
{% endwith %}
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% translate 'Save' %}">{% endif %}
</p>