diff --git a/src/apps/api/pagination.py b/src/apps/api/pagination.py index 5f3cbdc41..f0e07d5a0 100644 --- a/src/apps/api/pagination.py +++ b/src/apps/api/pagination.py @@ -22,3 +22,64 @@ def get_paginated_response(self, data): 'page_size': self.page_size, 'results': data }) + + +class DynamicChoicePagination(PageNumberPagination): + """ + Pagination dynamique pour l'UI : + - défaut : 50 + - valeurs autorisées côté client : 50, 100, 500, all + - si page_size=all => on renvoie tous les objets (dans la limite de max_page_size) + """ + page_size = 50 + page_size_query_param = 'page_size' + max_page_size = 1000 + _allowed_sizes = (50, 100, 500, 'all') + + def get_page_size(self, request): + raw = request.query_params.get(self.page_size_query_param) + if raw is None: + return self.page_size + + raw_lower = str(raw).lower() + if raw_lower == 'all': + return None + + try: + val = int(raw) + except (TypeError, ValueError): + return self.page_size + + if val in (50, 100, 500): + return val + return self.page_size + + def paginate_queryset(self, queryset, request, view=None): + raw = request.query_params.get(self.page_size_query_param) + self.requested_page_size = raw if raw is not None else str(self.page_size) + + if raw is not None and str(raw).lower() == 'all': + try: + total = queryset.count() + except Exception: + total = self.max_page_size + self.page_size = total if (isinstance(total, int) and total > 0) else 1 + else: + page_size = self.get_page_size(request) + if page_size is None: + page_size = self.page_size + self.page_size = page_size + + return super().paginate_queryset(queryset, request, view) + + def get_paginated_response(self, data): + page_size_value = self.requested_page_size if getattr(self, 'requested_page_size', None) is not None else self.page_size + + return Response({ + 'next': self.get_next_link(), + 'previous': self.get_previous_link(), + 'count': self.page.paginator.count, + 'page_size': page_size_value, + 'results': data, + 'allowed_page_sizes': [50, 100, 500, 'all'], + }) \ No newline at end of file diff --git a/src/apps/api/views/submissions.py b/src/apps/api/views/submissions.py index 7c7ddb538..89b77a185 100644 --- a/src/apps/api/views/submissions.py +++ b/src/apps/api/views/submissions.py @@ -16,6 +16,7 @@ from django.core.files.base import ContentFile from profiles.models import Organization, Membership +from api.pagination import DynamicChoicePagination from tasks.models import Task from api.serializers.submissions import SubmissionCreationSerializer, SubmissionSerializer, SubmissionFilesSerializer, SubmissionDetailSerializer from competitions.models import Submission, SubmissionDetails, Phase, CompetitionParticipant @@ -32,6 +33,7 @@ class SubmissionViewSet(ModelViewSet): filter_fields = ('phase__competition', 'phase', 'status', 'is_soft_deleted') search_fields = ('data__data_file', 'description', 'name', 'owner__username') renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [renderers.CSVRenderer] + pagination_class = DynamicChoicePagination def check_object_permissions(self, request, obj): if self.action in ['submission_leaderboard_connection']: diff --git a/src/static/riot/competitions/detail/submission_manager.tag b/src/static/riot/competitions/detail/submission_manager.tag index 5ffe959ef..a0dc6a90a 100644 --- a/src/static/riot/competitions/detail/submission_manager.tag +++ b/src/static/riot/competitions/detail/submission_manager.tag @@ -187,6 +187,37 @@ +