Как реализовать разбиение на страницы для фильтров боковой панели администратора Django 5?

Проблема

Фильтры боковой панели администратора Django отображают все параметры без разбивки на страницы, что становится громоздким, когда у вас есть сотни связанных объектов:

By Study
• All
• Study-001: Genetic markers in mice
• Study-002: Effects of caffeine
...
• Study-999: Soil microbiome analysis

При большом количестве опций это делает пользовательский интерфейс непригодным для использования и снижает производительность.

Наш подход

Мы внедрили пользовательские фильтры с разбивкой на страницы, чтобы одновременно отображать только подмножество параметров:

By Study
• All
• Study-001: Genetic markers in mice
• Study-002: Effects of caffeine
...
• Study-010: Plant growth factors
Page 1 of 100 | Next >

Реализация

  1. Пользовательский класс фильтра:
class StudyListFilter(SimpleListFilter):
    title = _('By Study')
    parameter_name = 'study__id__exact'
    template = 'admin/filter_pagination.html'  # Custom template

    def lookups(self, request, model_admin):
        # Return minimal data - real items are provided in the template
        return [('', 'All')]

    def queryset(self, request, queryset):
        if self.value():
            return queryset.filter(study__id=self.value())
        return queryset
  1. Измененный класс администратора:
@admin.register(Assay)
class AssayAdmin(admin.ModelAdmin):
    list_filter = (StudyListFilter, 'measurement_type')
    change_list_template = 'admin/study_change_list.html'
    
    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        
        # Get paginated studies
        studies = Study.objects.all().order_by('id')
        paginator = Paginator(studies, 10)
        page_number = request.GET.get('filter_page', 1)
        page_obj = paginator.get_page(page_number)
        
        # Pass pagination data to template
        extra_context.update({
            'filter_page_obj': page_obj,
            'filter_items': [(s.id, f"{s.accession_code} - {s.title[:30]}") for s in page_obj],
            'filter_name': 'study__id__exact',
            'filter_title': 'By Study',
        })
        
        return super().changelist_view(request, extra_context)
  1. Пользовательский шаблон для фильтра:
<h3>{{ title }}</h3>
<ul>
  <li {% if not spec.value %}class="selected"{% endif %}>
    <a href="?">All</a>
  </li>
  {% for id, name in filter_items %}
    <li {% if spec.value == id|stringformat:'s' %}class="selected"{% endif %}>
      <a href="?{{ filter_name }}={{ id }}">{{ name }}</a>
    </li>
  {% endfor %}
  
  {% if filter_page_obj.has_other_pages %}
    <li class="pagination">
      {% if filter_page_obj.has_previous %}
        <a href="?filter_page={{ filter_page_obj.previous_page_number }}">Previous</a>
      {% endif %}
      Page {{ filter_page_obj.number }} of {{ filter_page_obj.paginator.num_pages }}
      {% if filter_page_obj.has_next %}
        <a href="?filter_page={{ filter_page_obj.next_page_number }}">Next</a>
      {% endif %}
    </li>
  {% endif %}
</ul>

Результат

Кнопки для разбивки на страницы отображаются, но не работают.

enter image description here

# The button points to 
http://localhost:8000/admin/isa_api/assay/?e=1

Есть ли более простой способ архивировать желаемый результат?

Вернуться на верх