""" Defines the views for the API """ # from django.shortcuts import render from rest_framework import viewsets from rest_framework.views import APIView from rest_framework.response import Response from django.shortcuts import get_object_or_404 from django.http import HttpResponse from .pagination import PageNumberWithPageSizePagination from .serializers import ( SmallSportListSerializer, SportListSerializer, CriterionListSerializer, QuestionListSerializer, SingleSportSerializer, CriteriaSerializer, IncompleteSportSerializer, ) from .models import Sport, Criterion, Question # Create your views here. class SportListView(viewsets.ModelViewSet): # pylint: disable=too-many-ancestors """ A View returning every Sport Object """ serializer_class = SportListSerializer queryset = Sport.objects.all() class CriterionListView(viewsets.ModelViewSet): # pylint: disable=too-many-ancestors """ A View returning every Criterion Object """ serializer_class = CriterionListSerializer queryset = Criterion.objects.all() class QuestionListView(viewsets.ModelViewSet): # pylint: disable=too-many-ancestors """ A View returning every Question Object """ serializer_class = QuestionListSerializer queryset = Question.objects.all() # Dev Notes: # - If we want to include a View in the Router in urls.py, the View needs to be a Viewset # - Those are mostly meant for Lists of Objects, so instead of get() and post(), list() and create() are used respectively # https://stackoverflow.com/questions/30389248/how-can-i-register-a-single-view-not-a-viewset-on-my-router class SmallSportListView(viewsets.ViewSet): """ View for Sports and List of Sport: List returns every Sport with the is_filled Field Detail returns single Sports with every Criterium """ authentication_classes = [] # GET for api/admin/sport/ def list(self, request): """ GET for api/admin/sport/ Returns a List of Every Sport with the is_filled Field, stating whether every Criterion is given a Rating or not """ paginator = PageNumberWithPageSizePagination() sports = Sport.objects.all().order_by("name") sports = paginator.paginate_queryset(sports, request) is_filled_tuples = [] for sport in sports: is_filled_tuples.append((sport, sport.is_filled())) serializer = SmallSportListSerializer(is_filled_tuples) return paginator.get_paginated_response(serializer.data) # POST for api/admin/sport/ def create(self, request): """ POST for api/admin/sport/ View for Creating a New Sport """ request_data = SingleSportSerializer().to_internal_value(request) # A Try at Error Catching if request_data is None: return HttpResponse(status=400) new_sport = Sport.objects.create_sport() new_sport.name = request_data["name"] new_sport.url = request_data["url"] new_sport.save() response = SingleSportSerializer(new_sport) return Response(response.data) # GET for api/admin/sport/<id>/ def retrieve(self, request, pk=None): """ GET for api/admin/sport/<pk>/ View for getting a Single Sport, with the pk to the Sport being the argument in the URL """ sport = get_object_or_404(Sport, pk=pk) response = SingleSportSerializer(sport) return Response(response.data) # PUT for api/admin/sport/<id>/ def update(self, request, pk=None): """ PUT for api/admin/sport/<id>/ Creates a Sport if it doesn't exist, otherwise overwrites it. TODO: Maybe Rework PUT if needed of Admin Frontend """ # Get Data from Serializer request_data = SingleSportSerializer().to_internal_value(request) if request_data is None: # Something is Broke, so Refuse Changing Data return HttpResponse(status=400) # Get Sport from Data sport = Sport.objects.get(pk=pk) # Apply New Data to Sport sport.name = request_data["name"] sport.url = request_data["url"] # Overwrite Criterion Ratings for criterion, value in request_data["criteria"]: sport.rate(criterion, value) # Re-Serialize changed Sport and Send it back response = SingleSportSerializer(sport) return Response(response.data) # PATCH for api/admin/sport/<id>/ def partial_update(self, request, pk=None): """ PATCH for api/admin/sport/<id>/ Fills in the given Values into the Sport specified in the URL """ # Get Data from Serializer request_data = SingleSportSerializer().to_internal_value(request) if request_data is None: # Something is Broke, so Refuse Changing Data return HttpResponse(status=400) # Get Sport from Data sport = Sport.objects.get(pk=pk) # Apply New Data to Sport, if it exists if "name" in request_data.keys(): sport.name = request_data["name"] if "url" in request_data.keys(): sport.url = request_data["url"] # Overwrite Criterion Ratings for criterion, value in request_data["criteria"]: sport.rate(criterion, value) # Re-Serialize changed Sport and Send it back response = SingleSportSerializer(sport) return Response(response.data) # DELETE for api/admin/sport/<id>/ def destroy(self, request, pk=None): """ DELETE for api/admin/sport/<id>/ Removes Sport Object specified in the URL """ sport = get_object_or_404(Sport, pk=pk) sport.delete() return HttpResponse(status=404) class IncompleteSportView(APIView): """ Returns all Sport Objects with Incomplete Ratings """ authentication_classes = [] # GET for api/admin/sport/incomplete/ def get(self, request): """ GET for api/admin/sport/incomplete/ Returns every incomplete Sport with its incomplete Ratings in a paginated manner """ paginator = PageNumberWithPageSizePagination() queryset = Sport.objects.iterator() queryset = paginator.paginate_queryset(queryset, request) incomplete_sport_list = [] for sport in queryset: if not sport.is_filled(): incomplete_sport_list.append(sport) response = IncompleteSportSerializer(incomplete_sport_list) return paginator.get_paginated_response(response.data) class CriteriaView(APIView): """ View for the List of Criteria and their Metadata """ authentication_classes = [] # GET for api/admin/criteria/ def get(self, request): """ GET for api/admin/criteria/ Returns every Criterium and the Metadata of Number of Sports in which the Rating is >1 and the cumulated sum of Ratings >1 TODO: Also Pagination """ data = [] for crit in Criterion.objects.iterator(): active_sports, sum_of_weights = crit.get_active_sum() data.append((crit, active_sports, sum_of_weights)) response = CriteriaSerializer(data) return Response(response.data)