Skip to content
Snippets Groups Projects
Commit 4f628891 authored by Konrad Mohrfeldt's avatar Konrad Mohrfeldt :koala:
Browse files

feat: add new search & order filters for episodes endpoint

parent e4b8bcdb
No related branches found
No related tags found
No related merge requests found
......@@ -5,7 +5,7 @@ from django_filters import rest_framework as filters
from django_filters import widgets
from django import forms
from django.db.models import Exists, OuterRef, QuerySet
from django.db.models import Exists, OuterRef, Q, QuerySet
from django.utils import timezone
from program import models
from program.services import generate_program_entries
......@@ -21,6 +21,21 @@ class StaticFilterHelpTextMixin:
return _filter
class StaticQueryBooleanFilter(filters.BooleanFilter):
def __init__(self, *args, query: Q | None = None, **kwargs):
if query is None:
raise ValueError("query must not be None or unset.")
self.query = query
super().__init__(*args, **kwargs)
def filter(self, qs, value):
if value is True:
return qs.filter(self.query)
if value is False:
return qs.filter(~self.query)
return qs
class IntegerInFilter(filters.BaseInFilter):
class QueryArrayWidget(widgets.QueryArrayWidget):
# see: https://github.com/carltongibson/django-filter/issues/1047
......@@ -261,6 +276,9 @@ class TimeSlotFilterSet(filters.FilterSet):
class EpisodeFilterSet(StaticFilterHelpTextMixin, filters.FilterSet):
order = filters.OrderingFilter(
fields=["title", "id", "updated_at", "updated_by", "has_timeslots"],
)
ids = IntegerInFilter(
field_name="id",
help_text="Return only episodes matching the specified id(s).",
......@@ -277,6 +295,16 @@ class EpisodeFilterSet(StaticFilterHelpTextMixin, filters.FilterSet):
field_name="timeslots",
help_text="Return only episodes that belong to the specified timeslot(s).",
)
has_timeslots = filters.BooleanFilter(
label="Has timeslots",
help_text="Returns only timeslots that either have or have not any timeslots.",
)
has_title = StaticQueryBooleanFilter(
query=~Q(title=""),
help_text=(
"If true returns episodes with titles. If false returns episodes without titles."
),
)
class Meta:
model = models.Episode
......@@ -285,6 +313,7 @@ class EpisodeFilterSet(StaticFilterHelpTextMixin, filters.FilterSet):
"show_ids",
"show_owner_ids",
"timeslot_ids",
"order",
]
......
......@@ -47,6 +47,7 @@ from rest_framework.response import Response
from django.conf import settings
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.db.models import Q
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404
from django.utils import timezone
......@@ -1381,10 +1382,12 @@ class EpisodeOwnershipPermission(BasePermission):
destroy=extend_schema(summary="Delete an existing episode."),
)
class APIEpisodeViewSet(viewsets.ModelViewSet):
filterset_class = filters.EpisodeFilterSet
queryset = Episode.objects.all().annotate(has_timeslots=Q(timeslots__isnull=True)).distinct()
pagination_class = LimitOffsetPagination
serializer_class = EpisodeSerializer
queryset = Episode.objects.all()
filter_backends = [DjangoFilterBackend, drf_filters.SearchFilter]
filterset_class = filters.EpisodeFilterSet
search_fields = ["title", "summary", "content"]
permission_classes = [
DjangoModelPermissionsOrAnonReadOnly,
EpisodeOwnershipPermission,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment