Coverage for api\serializers\evenement.py: 70%
44 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-13 15:18 +0200
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-13 15:18 +0200
1"""
2Module contenant le sérialiseur pour le modèle Evenement.
4Ce module définit la sérialisation/désérialisation des données des événements
5sportifs pour l'API REST, incluant la gestion des relations avec les épreuves et lieux.
6"""
7from rest_framework import serializers
8from api.models import Evenement, Lieu, Epreuve
9from api.serializers.lieu import LieuSerializer
10from api.serializers.epreuve import EpreuveSerializer
13class EvenementSerializer(serializers.ModelSerializer):
14 """
15 Sérialiseur pour le modèle Evenement.
17 Gère la sérialisation des événements avec leurs relations aux épreuves et lieux.
18 Permet l'assignation d'épreuves à un événement tout en évitant les conflits.
20 :ivar epreuves: Liste des épreuves associées (lecture seule)
21 :type epreuves: list of EpreuveSerializer
22 :ivar epreuve_ids: IDs des épreuves à associer (écriture seule)
23 :type epreuve_ids: PrimaryKeyRelatedField
24 :ivar lieu: Données complètes du lieu (lecture seule)
25 :type lieu: LieuSerializer
26 :ivar lieu_id: ID du lieu pour l'écriture
27 :type lieu_id: PrimaryKeyRelatedField
28 """
29 epreuves = EpreuveSerializer(many=True, read_only=True)
30 epreuve_ids = serializers.PrimaryKeyRelatedField(
31 queryset=Epreuve.objects.all(),
32 many=True,
33 write_only=True,
34 source='epreuves',
35 required=False
36 )
37 lieu = LieuSerializer(read_only=True)
38 lieu_id = serializers.PrimaryKeyRelatedField(
39 queryset=Lieu.objects.all(),
40 write_only=True,
41 source='lieu'
42 )
44 class Meta:
45 """
46 Configuration du sérialiseur.
48 :cvar model: Modèle Django associé au sérialiseur
49 :type model: Evenement
50 :cvar fields: Champs inclus dans la sérialisation
51 :type fields: list
52 """
53 model = Evenement
54 fields = [
55 'id', 'description',
56 'lieu', 'lieu_id',
57 'date', 'horraire',
58 'epreuves', 'epreuve_ids',
59 'nb_place_total', 'nb_place_restante'
60 ]
62 def validate_epreuve_ids(self, value):
63 """
64 Valide les IDs des épreuves à associer à l'événement.
66 Vérifie qu'aucune épreuve n'est déjà assignée à un autre événement
67 pour éviter les conflits d'assignation.
69 :param value: Liste des épreuves à valider
70 :type value: list of Epreuve
71 :return: Liste des épreuves validées
72 :rtype: list of Epreuve
73 :raises serializers.ValidationError: Si des épreuves sont déjà assignées ailleurs
74 """
75 if not value:
76 return value
78 # Vérifier les conflits en excluant l'événement actuel (si modification)
79 instance_id = self.instance.id if self.instance else None
80 conflits = []
82 for epreuve in value:
83 if epreuve.evenement_id is not None and epreuve.evenement_id != instance_id:
84 conflits.append(epreuve)
86 if conflits:
87 raise serializers.ValidationError(
88 f"Les épreuves suivantes sont déjà assignées à d'autres événements : {[e.id for e in conflits]}"
89 )
90 return value
92 def create(self, validated_data):
93 """
94 Crée un nouvel événement avec ses épreuves associées.
96 :param validated_data: Données validées pour la création
97 :type validated_data: dict
98 :return: L'événement créé avec ses épreuves assignées
99 :rtype: Evenement
100 """
101 epreuves = validated_data.pop('epreuves', [])
102 evenement = Evenement.objects.create(**validated_data)
104 for epreuve in epreuves:
105 epreuve.evenement = evenement
106 epreuve.save()
108 return evenement
110 def update(self, instance, validated_data):
111 """
112 Met à jour un événement et gère les épreuves associées.
114 Désassocie les anciennes épreuves et assigne les nouvelles si présentes.
116 :return: L'événement mis à jour
117 """
118 epreuves = validated_data.pop('epreuves', None)
120 for attr, value in validated_data.items():
121 setattr(instance, attr, value)
122 instance.save()
124 if epreuves is not None:
125 nouveaux_ids = {e.pk for e in epreuves}
126 anciens_ids = set(instance.epreuves.values_list('id', flat=True))
128 # Désassocier les épreuves qui ne sont plus dans la liste
129 instance.epreuves.filter(id__in=anciens_ids - nouveaux_ids).update(evenement=None)
131 # Associer les nouvelles épreuves
132 for epreuve in epreuves:
133 if epreuve.pk not in anciens_ids:
134 epreuve.evenement = instance
135 epreuve.save()
137 return instance