Фреймворк 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()
, которое помогло мне отследить это 🙌
Один из тех моментов, когда “это работает в одной вкладке, но не в той, которую вы тестируете” 😅 Еще раз спасибо!