Files
hoopscout/apps/api/views.py
2026-03-10 15:53:55 +01:00

100 lines
3.2 KiB
Python

from rest_framework import generics
from rest_framework import status
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
from apps.competitions.models import Competition, Season
from apps.players.forms import PlayerSearchForm
from apps.players.models import Player
from apps.players.services.search import (
METRIC_SORT_KEYS,
annotate_player_metrics,
apply_sorting,
base_player_queryset,
filter_players,
)
from apps.teams.models import Team
from .permissions import ReadOnlyOrDeny
from .serializers import (
CompetitionSerializer,
PlayerDetailSerializer,
PlayerListSerializer,
SeasonSerializer,
TeamSerializer,
)
class ApiPagination(PageNumberPagination):
page_size = 20
page_size_query_param = "page_size"
max_page_size = 100
class ReadOnlyBaseAPIView:
permission_classes = [ReadOnlyOrDeny]
throttle_classes = [AnonRateThrottle, UserRateThrottle]
class PlayerSearchApiView(ReadOnlyBaseAPIView, generics.ListAPIView):
serializer_class = PlayerListSerializer
pagination_class = ApiPagination
def get_search_form(self):
if not hasattr(self, "_search_form"):
self._search_form = PlayerSearchForm(self.request.query_params)
return self._search_form
def _validation_error_response(self):
form = self.get_search_form()
return Response(
{
"detail": "Invalid search parameters.",
"errors": form.errors.get_json_data(escape_html=True),
},
status=status.HTTP_400_BAD_REQUEST,
)
def list(self, request, *args, **kwargs):
form = self.get_search_form()
if form.is_bound and not form.is_valid():
return self._validation_error_response()
return super().list(request, *args, **kwargs)
def get_queryset(self):
form = self.get_search_form()
queryset = base_player_queryset()
queryset = filter_players(queryset, form.cleaned_data)
sort_key = form.cleaned_data.get("sort", "name_asc")
if sort_key in METRIC_SORT_KEYS:
queryset = annotate_player_metrics(queryset, form.cleaned_data)
queryset = apply_sorting(queryset, sort_key)
return queryset
class PlayerDetailApiView(ReadOnlyBaseAPIView, generics.RetrieveAPIView):
serializer_class = PlayerDetailSerializer
queryset = Player.objects.select_related(
"nationality",
"nominal_position",
"inferred_role",
"origin_competition",
"origin_team",
).prefetch_related("aliases")
class CompetitionListApiView(ReadOnlyBaseAPIView, generics.ListAPIView):
serializer_class = CompetitionSerializer
queryset = Competition.objects.select_related("country").order_by("name")
class TeamListApiView(ReadOnlyBaseAPIView, generics.ListAPIView):
serializer_class = TeamSerializer
queryset = Team.objects.select_related("country").order_by("name")
class SeasonListApiView(ReadOnlyBaseAPIView, generics.ListAPIView):
serializer_class = SeasonSerializer
queryset = Season.objects.order_by("-start_date")