roosterwijs/backend/core/serializers.py

225 lines
8.5 KiB
Python

"""DRF-serializers voor het kerndomein."""
from rest_framework import serializers
from .models import (
Activiteit, Afwezigheid, BlokUitzondering, Functie, Groep, KalenderDag,
Locatie, Persoon, Roosterblok, Schooljaar, Subgroep, Tijdslot,
)
class FunctieSerializer(serializers.ModelSerializer):
aantal_personen = serializers.IntegerField(source="personen.count", read_only=True)
class Meta:
model = Functie
fields = ["id", "naam", "omschrijving", "actief", "aantal_personen", "aangemaakt_op"]
read_only_fields = ["aangemaakt_op"]
class GroepSerializer(serializers.ModelSerializer):
aantal_leerlingen = serializers.IntegerField(source="leerlingen.count", read_only=True)
class Meta:
model = Groep
fields = ["id", "naam", "omschrijving", "actief", "aantal_leerlingen", "aangemaakt_op"]
read_only_fields = ["aangemaakt_op"]
class PersoonSerializer(serializers.ModelSerializer):
volledige_naam = serializers.CharField(read_only=True)
rol_label = serializers.CharField(source="get_rol_display", read_only=True)
groep_naam = serializers.CharField(source="groep.naam", read_only=True, default=None)
functies = serializers.PrimaryKeyRelatedField(
many=True, queryset=Functie.objects.all(), required=False
)
functies_namen = serializers.SerializerMethodField()
class Meta:
model = Persoon
fields = [
"id", "voornaam", "achternaam", "volledige_naam",
"rol", "rol_label", "groep", "groep_naam",
"functies", "functies_namen",
"actief", "opmerkingen", "aangemaakt_op",
]
read_only_fields = ["aangemaakt_op"]
def get_functies_namen(self, obj):
return [{"id": f.id, "naam": f.naam} for f in obj.functies.all()]
def validate(self, data):
# Functies horen alleen bij medewerkers; een leerling krijgt er geen.
# (De M2M wordt door DRF ná save() gezet, dus hier afdwingen.)
rol = data.get("rol", getattr(self.instance, "rol", None))
if rol == "leerling":
data["functies"] = []
return data
class SubgroepSerializer(serializers.ModelSerializer):
leden = serializers.PrimaryKeyRelatedField(
many=True, queryset=Persoon.objects.filter(rol="leerling"), required=False
)
leden_namen = serializers.SerializerMethodField()
aantal_leden = serializers.SerializerMethodField()
class Meta:
model = Subgroep
fields = [
"id", "naam", "omschrijving", "actief",
"leden", "leden_namen", "aantal_leden", "aangemaakt_op",
]
read_only_fields = ["aangemaakt_op"]
def get_leden_namen(self, obj):
return [{"id": p.id, "naam": p.volledige_naam} for p in obj.leden.all()]
def get_aantal_leden(self, obj):
return obj.leden.count()
# --- Fase 2 ---------------------------------------------------------------
class SchooljaarSerializer(serializers.ModelSerializer):
class Meta:
model = Schooljaar
fields = ["id", "naam", "start_datum", "eind_datum", "actief"]
def validate(self, data):
start = data.get("start_datum", getattr(self.instance, "start_datum", None))
eind = data.get("eind_datum", getattr(self.instance, "eind_datum", None))
if start and eind and eind <= start:
raise serializers.ValidationError("De einddatum moet na de startdatum liggen.")
return data
class KalenderDagSerializer(serializers.ModelSerializer):
type_label = serializers.CharField(source="get_type_display", read_only=True)
class Meta:
model = KalenderDag
fields = ["id", "schooljaar", "datum", "type", "type_label", "omschrijving"]
class TijdslotSerializer(serializers.ModelSerializer):
dag_label = serializers.CharField(source="get_dag_display", read_only=True)
class Meta:
model = Tijdslot
fields = ["id", "naam", "dag", "dag_label", "start_tijd", "eind_tijd", "volgorde", "actief"]
def validate(self, data):
start = data.get("start_tijd", getattr(self.instance, "start_tijd", None))
eind = data.get("eind_tijd", getattr(self.instance, "eind_tijd", None))
if start and eind and eind <= start:
raise serializers.ValidationError("De eindtijd moet na de starttijd liggen.")
return data
class ActiviteitSerializer(serializers.ModelSerializer):
kleur = serializers.RegexField(
regex=r"^#[0-9a-fA-F]{6}$",
error_messages={"invalid": "Kleur moet een hex-code zijn, bv. #2563eb."},
)
class Meta:
model = Activiteit
fields = ["id", "naam", "kleur", "omschrijving", "actief"]
class LocatieSerializer(serializers.ModelSerializer):
class Meta:
model = Locatie
fields = ["id", "naam", "omschrijving", "actief"]
class RoosterblokSerializer(serializers.ModelSerializer):
activiteit_naam = serializers.CharField(source="activiteit.naam", read_only=True)
activiteit_kleur = serializers.CharField(source="activiteit.kleur", read_only=True)
tijdslot_label = serializers.CharField(source="tijdslot.__str__", read_only=True)
locatie_naam = serializers.CharField(source="locatie.naam", read_only=True, default=None)
doel_type = serializers.CharField(read_only=True)
doel_naam = serializers.SerializerMethodField()
begeleiders_namen = serializers.SerializerMethodField()
class Meta:
model = Roosterblok
fields = [
"id", "schooljaar", "tijdslot", "tijdslot_label",
"activiteit", "activiteit_naam", "activiteit_kleur",
"locatie", "locatie_naam",
"groep", "subgroep", "leerling", "doel_type", "doel_naam",
"begeleiders", "begeleiders_namen", "opmerkingen", "aangemaakt_op",
]
read_only_fields = ["aangemaakt_op"]
def get_doel_naam(self, obj):
if obj.groep_id:
return obj.groep.naam
if obj.subgroep_id:
return obj.subgroep.naam
if obj.leerling_id:
return obj.leerling.volledige_naam
return None
def get_begeleiders_namen(self, obj):
return [{"id": p.id, "naam": p.volledige_naam} for p in obj.begeleiders.all()]
def validate(self, data):
# Precies één doelgroep (groep / subgroep / leerling).
groep = data.get("groep", getattr(self.instance, "groep", None))
subgroep = data.get("subgroep", getattr(self.instance, "subgroep", None))
leerling = data.get("leerling", getattr(self.instance, "leerling", None))
gevuld = [x for x in (groep, subgroep, leerling) if x]
if len(gevuld) != 1:
raise serializers.ValidationError(
"Kies precies één doelgroep: groep, subgroep of leerling."
)
# Begeleiders zijn medewerkers; een leerling kan geen begeleider zijn.
# (Het Roosterblok-model kent geen rolbeperking, dus hier afdwingen.)
for p in data.get("begeleiders", []):
if p.rol == "leerling":
raise serializers.ValidationError(
f"'{p.volledige_naam}' is een leerling en kan geen begeleider zijn."
)
return data
class AfwezigheidSerializer(serializers.ModelSerializer):
persoon_naam = serializers.CharField(source="persoon.volledige_naam", read_only=True)
persoon_rol = serializers.CharField(source="persoon.rol", read_only=True)
class Meta:
model = Afwezigheid
fields = [
"id", "persoon", "persoon_naam", "persoon_rol",
"start_datum", "eind_datum", "reden", "aangemaakt_op",
]
read_only_fields = ["aangemaakt_op"]
def validate(self, data):
start = data.get("start_datum", getattr(self.instance, "start_datum", None))
eind = data.get("eind_datum", getattr(self.instance, "eind_datum", None))
if start and eind and eind < start:
raise serializers.ValidationError("De einddatum ligt vóór de startdatum.")
return data
class BlokUitzonderingSerializer(serializers.ModelSerializer):
vervanger_naam = serializers.CharField(
source="vervanger.volledige_naam", read_only=True, default=None
)
class Meta:
model = BlokUitzondering
fields = [
"id", "roosterblok", "datum", "vervalt",
"vervanger", "vervanger_naam", "opmerking",
]
def validate_vervanger(self, value):
if value is not None and value.rol == "leerling":
raise serializers.ValidationError(
"Een leerling kan geen vervanger zijn."
)
return value