Фреймворк Django REST `pagination_class` в ViewSet игнорируется

Опишите проблему

У меня есть ModelViewSet в Django REST Framework, предназначенный для возврата списка Order объектов. Чтобы повысить производительность, я пытаюсь реализовать пользовательскую разбивку на страницы, которая ограничивает количество результатов до 65 на страницу.

Несмотря на установку свойства pagination_class непосредственно в моем ViewSet, конечная точка API продолжает возвращать полный набор запросов без разбивки по страницам (более 300 объектов). Похоже, мой пользовательский класс разбивки на страницы полностью игнорируется.

Моя цель состоит в том, чтобы API возвращал разбитый на страницы ответ с count, next, previous, и results списком, содержащим максимум 65 элементов когда я запрашиваю .../api/orders/?page=1.

То, что я пробовал

Вот мои настройки:

1. pagination.py: Я создал пользовательский класс разбивки на страницы.

# my_app/pagination.py
from rest_framework.pagination import PageNumberPagination

class CustomOrderPagination(PageNumberPagination):
    page_size = 65
    page_size_query_param = 'page_size'
    max_page_size = 100

2. views.py: Я присвоил этот пользовательский класс своему ViewSet. Набор запросов использует select_related и prefetch_related для повышения производительности.

# my_app/views.py
from rest_framework import viewsets
from django.db.models import Sum
from .models import Order
from .serializers import OrderSlimSerializer
from .pagination import CustomOrderPagination

class OrderViewSet(viewsets.ModelViewSet):
    # I explicitly set the pagination class here
    pagination_class = CustomOrderPagination

    serializer_class = OrderSlimSerializer
    queryset = Order.objects.select_related('client').prefetch_related(
        'orderitem_set__location__service_plan'
    ).annotate(
        total_amount=Sum('orderitem_set__service_plan__service_fee')
    )
    # ... (permission_classes, filter_backends, etc.) ...

3. serializers.py: Я использую оптимизированные "тонкие" сериализаторы, чтобы сохранить небольшую полезную нагрузку.

# my_app/serializers.py
class LocationItemSerializer(serializers.ModelSerializer):
    # ... returns a small payload for each location ...
    class Meta:
        model = OrderItem
        fields = ['location_name', 'service_plan_details']

class OrderSlimSerializer(serializers.ModelSerializer):
    client_name = serializers.CharField(source='client.name')
    locations = LocationItemSerializer(source='orderitem_set', many=True)
    charge_amount = serializers.DecimalField(source='total_amount', read_only=True)

    class Meta:
        model = Order
        fields = ['id', 'order_number', 'client_name', 'locations', 'charge_amount']

4. Запрос: Я правильно формулирую запрос с параметром page.

curl "http://localhost:8000/api/orders/?page=1"

5. Разбивка на страницы настроена в Settings.py:

REST_FRAMEWORK = {
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 100,
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.BasicAuthentication",
        "rest_framework.authentication.SessionAuthentication",
        "rest_framework.authentication.TokenAuthentication",
        "rest_framework_simplejwt.authentication.JWTAuthentication",
    ],
}

Результат: Ответом является единый список из более чем 300 Order объектов, а не разбитый на страницы словарь, подобный {"count": 368, "next": ..., "results": [...]}.

Вопрос: Почему моя настройка pagination_class игнорируется в OrderViewSet и как правильно обеспечить применение этой пользовательской разбивки на страницы? Есть ли какая-то глобальная настройка, которую я, возможно, упустил, которая полностью отключает разбивку на страницы?

PS: Я также проверил этот вопрос, но поскольку он касается простого ViewSet, а не ModelViewSet, я не был уверен, как адаптировать его к моему случаю.

Спасибо за ответы!

Оказывается, проблема была на моей стороне — я определил CustomOrderPagination в отдельном pagination.py файле, но импортировал его из другого модуля, который на самом деле он не использовался ViewSet.

Для отладки я добавил:

def paginate_queryset(self, queryset):
    print("called paginate_queryset")
    return super().paginate_queryset(queryset)

Но ничего не было напечатано — и тогда я понял, что назначаю класс разбивки на страницы, который даже не загружается. Как только я исправил импорт и подтвердил, что используется правильный класс разбивки на страницы, все заработало, как ожидалось.

Ценю вашу помощь — особенно за предложение переопределить paginate_queryset(), которое помогло мне отследить это 🙌

<время работы/>

Один из тех моментов, когда “это работает в одной вкладке, но не в той, которую вы тестируете” 😅 Еще раз спасибо!

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