diff --git a/competition/filters.py b/competition/filters.py new file mode 100644 index 0000000..9d0d104 --- /dev/null +++ b/competition/filters.py @@ -0,0 +1,10 @@ +from django.db.models.manager import BaseManager +from django.utils.timezone import now +from django_filters import BooleanFilter + + +class UpcomingFilter(BooleanFilter): + def filter(self, qs: BaseManager, value: bool): + lookup_expr = 'gte' if value else 'lte' + lookup = '__'.join([self.field_name, lookup_expr]) + return qs.filter(**{lookup: now()}) diff --git a/competition/serializers.py b/competition/serializers.py index 1cf07c3..3222368 100644 --- a/competition/serializers.py +++ b/competition/serializers.py @@ -158,6 +158,16 @@ class Meta: event = serializers.PrimaryKeyRelatedField( queryset=models.Event.objects.all()) + def validate(self, attrs): + grade: models.Grade | None = attrs.get('grade') + event: models.Event | None = attrs.get('event') + if event and grade and ( + event.competition.min_years_until_graduation > grade.years_until_graduation + ): + raise ValidationError( + f'Ročník {grade.tag} nie je povolený pre {event.competition.name}') + return super().validate(attrs) + @ts_interface(context='competition') class ProblemCorrectionSerializer(serializers.ModelSerializer): diff --git a/competition/views.py b/competition/views.py index a4e43ee..233dc89 100644 --- a/competition/views.py +++ b/competition/views.py @@ -1,3 +1,4 @@ +# pylint:disable=too-many-lines import csv import json import os @@ -9,10 +10,11 @@ from django.core.exceptions import ValidationError as CoreValidationError from django.core.files import File from django.core.mail import send_mail +from django.db.models.manager import BaseManager from django.http import FileResponse, HttpResponse from django.template.loader import render_to_string from django.utils.timezone import now -from django_filters import Filter, FilterSet +from django_filters import Filter, FilterSet, ModelChoiceFilter from django_filters.rest_framework import DjangoFilterBackend from rest_framework import exceptions, filters, mixins, status, viewsets from rest_framework.decorators import action @@ -22,6 +24,7 @@ from rest_framework.response import Response from base.utils import mime_type +from competition.filters import UpcomingFilter from competition.models import (Comment, Competition, CompetitionType, Event, EventRegistration, Grade, LateTag, Problem, Publication, PublicationType, Semester, Series, @@ -833,14 +836,30 @@ def post(self, request, format_post): class EventViewSet(ModelViewSetWithSerializerContext): """Ročníky akcií (napríklad Matboj 2021)""" + class EventFilterSet(FilterSet): + + class SuitableForGradeFilter(ModelChoiceFilter): + def filter(self, qs: BaseManager, value: Grade): + if value is None: + return qs + return qs.filter( + competition__min_years_until_graduation__lte=value.years_until_graduation + ) + + grade = SuitableForGradeFilter(queryset=Grade.objects.all()) + future = UpcomingFilter(field_name='end') + + class Meta: + model = Event + fields = ['school_year', + 'season_code', 'location', 'competition'] + queryset = Event.objects.all() serializer_class = EventSerializer - filterset_fields = ['school_year', 'competition', ] permission_classes = (CompetitionRestrictedPermission,) filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] - filterset_fields = ['school_year', - 'season_code', 'location', 'competition'] + filterset_class = EventFilterSet search_fields = ['competition__name', 'year', 'additional_name'] ordering_fields = ['start', 'end', 'year'] ordering = ['start']