admin.ModelAdmin.get_paginator() メソッドのしくみ


役割

ページネーション機能は、大量のデータセットを管理する場合に特に重要です。ページネータを使用することで、ユーザーは一度に表示される項目数を制限し、複数のページに分割されたデータセットを簡単にナビゲートできます。

メソッド引数

  • allow_empty_first_page: ページが空であっても最初のページを表示するかどうか
  • orphans: ページ末尾に表示される項目数の許容範囲
  • per_page: ページあたりの項目数
  • queryset: ページネーション対象のクエリセット

メソッドの動作

  1. メソッドは、まず設定された PAGINATOR_CLASS 属性に基づいてページネータクラスを取得します。デフォルトでは、django.core.paginator.EmptyPageException 例外を処理する django.core.paginator.Paginator クラスが使用されます。
  2. 次に、メソッドは queryset をページネータオブジェクトに渡して、ページネーション処理を実行します。
  3. 最後に、メソッドはページネーション処理の結果に基づいて、適切なページネータオブジェクトを返します。

カスタマイズ

admin.ModelAdmin.get_paginator() メソッドは、カスタムのページネータクラスを使用するようにオーバーライドできます。これにより、ページネーションの動作を独自に制御できます。

from django.core.paginator import Paginator

class MyModelAdmin(admin.ModelAdmin):
    def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True):
        # カスタムのページネータクラスを使用する
        return Paginator(queryset, per_page, orphans, allow_empty_first_page)
  • admin.ModelAdmin.get_paginator() メソッドは、管理サイトの change_list ビューで使用されます。


from django.core.paginator import Paginator

class MyModelAdmin(admin.ModelAdmin):
    def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True):
        # Set the page size to 10 items per page
        per_page = 10

        # Use the custom page size
        return Paginator(queryset, per_page, orphans, allow_empty_first_page)

In this example, the get_paginator() method is overridden to set the page size to 10 items per page. This means that only 10 items will be displayed on each page of the change list view.

Here is another example of how to use the get_paginator() method to use a custom page navigator class:

from django.core.paginator import Paginator
from myapp.paginator import MyCustomPaginator

class MyModelAdmin(admin.ModelAdmin):
    def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True):
        # Use the custom page navigator class
        return MyCustomPaginator(queryset, per_page, orphans, allow_empty_first_page)

In this example, the get_paginator() method is overridden to use a custom page navigator class called MyCustomPaginator. This class can be used to implement custom pagination behavior, such as displaying a different number of pages or using a different style of pagination links.



Using django.core.paginator.Paginator directly

You can directly create a Paginator instance and pass it to the change_list template context:

from django.core.paginator import Paginator

def changelist_view(self, request, object_id, queryset=None):
    # ...

    queryset, search_description, search_used = self.get_queryset(request)

    # Create a Paginator instance
    paginator = Paginator(queryset, self.paginator_num_per_page)

    # Get the current page number from the request
    page = request.GET.get('page')

    # Try to get the current page object
    try:
        page_obj = paginator.page(page)
    except PageNotfound:
        page_obj = paginator.page(1)

    # Pass the Paginator and page object to the template context
    context = {
        'object_list': page_obj.object_list,
        'paginator': page_obj,
        'search_description': search_description,
        'search_used': search_used,
    }

    # Return the rendered template
    return render(request, self.change_list_template, context)

Using custom middleware

Create custom middleware that intercepts the admin change list view and modifies the pagination data:

from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404

class CustomPaginationMiddleware:
    def process_view(self, request, view_func, view_args, view_kwargs):
        if view_func.view_class == admin.AdminChangeListView:
            # Get the model admin class
            model_admin = get_object_or_404(admin.site._registry, view_kwargs['model'])

            # Override the paginator class
            model_admin.paginator_class = MyCustomPaginator

            # Override the paginator number per page
            model_admin.paginator_num_per_page = 15

        return None

Using template inheritance

Create a custom base template for your admin change list views and override the pagination rendering logic:

{% extends 'admin/base.html' %}

{% block content %}
    {% for object in object_list %}
        {{ object }}
    {% endfor %}

    {% if paginator.num_pages > 1 %}
        <ul class="pagination">
            {% for page in paginator.page_range %}
                <li{% if page == paginator.current_page %} class="active"{% endif %}>
                    <a href="?page={{ page }}">{{ page }}</a>
                </li>
            {% endfor %}
        </ul>
    {% endif %}
{% endblock %}

Using third-party libraries

Consider using third-party libraries like django-infinite-pagination or django-rest-framework-datatables for more advanced pagination features.

  • Third-party libraries
    Evaluate the features and compatibility of third-party libraries before integrating them.
  • Flexibility
    Custom middleware or template inheritance provide more flexibility to modify pagination behavior across multiple admin views.
  • Complexity
    The complexity of each approach varies. Direct Paginator usage requires more template modifications, while middleware or template inheritance offer more centralized control.