from django.shortcuts import get_object_or_404 from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from .ballistics import compute_corrections from .models import FreePracticeSession, PRSSession, PRSStage, SpeedShootingSession from .serializers import ( FreePracticeSessionDetailSerializer, FreePracticeSessionListSerializer, FreePracticeSessionWriteSerializer, PRSSessionDetailSerializer, PRSSessionListSerializer, PRSSessionWriteSerializer, PRSStageSerializer, SpeedShootingSessionDetailSerializer, SpeedShootingSessionListSerializer, SpeedShootingSessionWriteSerializer, ) # ── PRS ─────────────────────────────────────────────────────────────────────── class PRSSessionViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] filterset_fields = ['date', 'is_public'] search_fields = ['name', 'location', 'notes', 'competition_name'] ordering_fields = ['date', 'created_at'] def get_queryset(self): qs = ( PRSSession.objects .filter(user=self.request.user) .select_related('rig', 'ammo', 'reloaded_batch__recipe', 'reloaded_batch__powder', 'analysis') ) if self.action != 'list': qs = qs.prefetch_related('stages') return qs def get_serializer_class(self): if self.action == 'list': return PRSSessionListSerializer if self.action in ('create', 'update', 'partial_update'): return PRSSessionWriteSerializer return PRSSessionDetailSerializer def perform_create(self, serializer): serializer.save(user=self.request.user) # ── Nested stage actions ────────────────────────────────────────────────── @action(detail=True, methods=['get', 'post'], url_path='stages') def stages(self, request, pk=None): session = self.get_object() if request.method == 'GET': serializer = PRSStageSerializer( session.stages.all(), many=True, context={'request': request} ) return Response(serializer.data) serializer = PRSStageSerializer( data=request.data, context={'request': request, 'session': session}, ) serializer.is_valid(raise_exception=True) serializer.save(session=session) return Response(serializer.data, status=status.HTTP_201_CREATED) @action(detail=True, methods=['get', 'patch', 'delete'], url_path=r'stages/(?P[^/.]+)') def stage_detail(self, request, pk=None, stage_pk=None): session = self.get_object() stage = get_object_or_404(PRSStage, pk=stage_pk, session=session) if request.method == 'GET': return Response(PRSStageSerializer(stage, context={'request': request}).data) if request.method == 'PATCH': serializer = PRSStageSerializer( stage, data=request.data, partial=True, context={'request': request} ) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) stage.delete() return Response(status=status.HTTP_204_NO_CONTENT) @action(detail=True, methods=['post'], url_path=r'stages/(?P[^/.]+)/compute-corrections') def compute_corrections_action(self, request, pk=None, stage_pk=None): session = self.get_object() stage = get_object_or_404(PRSStage, pk=stage_pk, session=session) return Response(compute_corrections(session, stage)) # ── Free Practice ───────────────────────────────────────────────────────────── class FreePracticeSessionViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] filterset_fields = ['date', 'is_public'] search_fields = ['name', 'location', 'notes'] ordering_fields = ['date', 'created_at'] def get_queryset(self): return ( FreePracticeSession.objects .filter(user=self.request.user) .select_related('rig', 'ammo', 'reloaded_batch__recipe', 'reloaded_batch__powder', 'analysis') ) def get_serializer_class(self): if self.action == 'list': return FreePracticeSessionListSerializer if self.action in ('create', 'update', 'partial_update'): return FreePracticeSessionWriteSerializer return FreePracticeSessionDetailSerializer def perform_create(self, serializer): serializer.save(user=self.request.user) # ── Speed Shooting ──────────────────────────────────────────────────────────── class SpeedShootingSessionViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] filterset_fields = ['date', 'is_public'] search_fields = ['name', 'location', 'notes', 'format'] ordering_fields = ['date', 'created_at'] def get_queryset(self): return ( SpeedShootingSession.objects .filter(user=self.request.user) .select_related('rig', 'ammo', 'reloaded_batch__recipe', 'reloaded_batch__powder', 'analysis') ) def get_serializer_class(self): if self.action == 'list': return SpeedShootingSessionListSerializer if self.action in ('create', 'update', 'partial_update'): return SpeedShootingSessionWriteSerializer return SpeedShootingSessionDetailSerializer def perform_create(self, serializer): serializer.save(user=self.request.user)