mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
refactor: Utilisation d'une application "Common" pour tous les modèles
de référence
This commit is contained in:
@ -4,3 +4,6 @@ from django.apps import AppConfig
|
||||
class CommonConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'Common'
|
||||
|
||||
def ready(self):
|
||||
import Common.signals
|
||||
@ -1,13 +1,59 @@
|
||||
from django.db import models
|
||||
|
||||
class StudentCompetency(models.Model):
|
||||
student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='competency_scores')
|
||||
competency = models.ForeignKey('School.Competency', on_delete=models.CASCADE, related_name='student_scores')
|
||||
score = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
|
||||
comment = models.TextField(blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('student', 'competency')
|
||||
class Domain(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
cycle = models.IntegerField(choices=[(1, 'Cycle 1'), (2, 'Cycle 2'), (3, 'Cycle 3'), (4, 'Cycle 4')])
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.student} - {self.competency.name} - Score: {self.score}"
|
||||
return f"{self.name} (Cycle {self.cycle})"
|
||||
|
||||
class Category(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
domain = models.ForeignKey(Domain, on_delete=models.CASCADE, related_name='categories')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Competency(models.Model):
|
||||
name = models.TextField()
|
||||
end_of_cycle = models.BooleanField(default=False, null=True, blank=True)
|
||||
level = models.CharField(max_length=50, null=True, blank=True)
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='competencies')
|
||||
|
||||
establishments = models.ManyToManyField(
|
||||
'Establishment.Establishment',
|
||||
through='School.EstablishmentCompetency',
|
||||
related_name='competencies',
|
||||
blank=True
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class PaymentPlanType(models.Model):
|
||||
code = models.CharField(max_length=50, unique=True)
|
||||
label = models.CharField(max_length=255)
|
||||
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
class PaymentModeType(models.Model):
|
||||
code = models.CharField(max_length=50, unique=True)
|
||||
label = models.CharField(max_length=255)
|
||||
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
class Cycle(models.Model):
|
||||
number = models.IntegerField(unique=True)
|
||||
label = models.CharField(max_length=50)
|
||||
|
||||
def __str__(self):
|
||||
return f"Cycle {self.number} - {self.label}"
|
||||
|
||||
class Level(models.Model):
|
||||
name = models.CharField(max_length=50)
|
||||
cycle = models.ForeignKey(Cycle, on_delete=models.CASCADE, related_name='levels')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
21
Back-End/Common/serializers.py
Normal file
21
Back-End/Common/serializers.py
Normal file
@ -0,0 +1,21 @@
|
||||
from rest_framework import serializers
|
||||
from Common.models import (
|
||||
Domain,
|
||||
Category,
|
||||
Competency
|
||||
)
|
||||
|
||||
class DomainSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Domain
|
||||
fields = '__all__'
|
||||
|
||||
class CategorySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Category
|
||||
fields = '__all__'
|
||||
|
||||
class CompetencySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Competency
|
||||
fields = '__all__'
|
||||
97
Back-End/Common/signals.py
Normal file
97
Back-End/Common/signals.py
Normal file
@ -0,0 +1,97 @@
|
||||
import json
|
||||
import os
|
||||
from django.db.models.signals import post_migrate
|
||||
from django.dispatch import receiver
|
||||
from Common.models import Domain, Category, Competency, PaymentModeType, PaymentPlanType, Cycle, Level
|
||||
|
||||
@receiver(post_migrate)
|
||||
def common_post_migrate(sender, **kwargs):
|
||||
if sender.name != "School":
|
||||
return
|
||||
|
||||
# Chemin absolu vers le répertoire Back-End
|
||||
backend_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Chemins vers les fichiers JSON
|
||||
json_files = [
|
||||
("Cycle1.json", 1),
|
||||
("Cycle2.json", 2),
|
||||
("Cycle3.json", 3),
|
||||
("Cycle4.json", 4),
|
||||
]
|
||||
|
||||
for file_name, cycle in json_files:
|
||||
json_file_path = os.path.join(backend_dir, "competences", file_name)
|
||||
|
||||
if not os.path.exists(json_file_path):
|
||||
print(f"Fichier JSON introuvable : {json_file_path}")
|
||||
continue
|
||||
|
||||
with open(json_file_path, 'r', encoding='utf-8') as file:
|
||||
data = json.load(file)
|
||||
|
||||
for domain_data in data['domaines']:
|
||||
# Vérifiez si le domaine existe déjà
|
||||
domain, _ = Domain.objects.get_or_create(name=domain_data['nom'], cycle=cycle)
|
||||
|
||||
for category_data in domain_data['categories']:
|
||||
# Vérifiez si la catégorie existe déjà
|
||||
category, _ = Category.objects.get_or_create(name=category_data['nom'], domain=domain)
|
||||
|
||||
for competency_data in category_data['competences']:
|
||||
# Vérifiez si la compétence existe déjà
|
||||
competency, _ = Competency.objects.get_or_create(
|
||||
name=competency_data['nom'],
|
||||
end_of_cycle=competency_data.get('fin_cycle', False),
|
||||
level=competency_data.get('niveau'),
|
||||
category=category
|
||||
)
|
||||
print(f"Données importées depuis : {json_file_path}")
|
||||
|
||||
payment_mode_types = [
|
||||
{"code": "SEPA", "label": "Prélèvement SEPA"},
|
||||
{"code": "TRANSFER", "label": "Virement"},
|
||||
{"code": "CHECK", "label": "Chèque"},
|
||||
{"code": "CASH", "label": "Espèce"},
|
||||
]
|
||||
for mode in payment_mode_types:
|
||||
PaymentModeType.objects.get_or_create(code=mode["code"], defaults={"label": mode["label"]})
|
||||
|
||||
payment_plan_types = [
|
||||
{"code": "ONE_TIME", "label": "1 fois"},
|
||||
{"code": "THREE_TIMES", "label": "3 fois"},
|
||||
{"code": "TEN_TIMES", "label": "10 fois"},
|
||||
{"code": "TWELVE_TIMES", "label": "12 fois"},
|
||||
]
|
||||
for plan in payment_plan_types:
|
||||
PaymentPlanType.objects.get_or_create(code=plan["code"], defaults={"label": plan["label"]})
|
||||
|
||||
# Création des cycles
|
||||
cycles_data = [
|
||||
{"number": 1, "label": "Cycle 1"},
|
||||
{"number": 2, "label": "Cycle 2"},
|
||||
{"number": 3, "label": "Cycle 3"},
|
||||
{"number": 4, "label": "Cycle 4"},
|
||||
]
|
||||
cycle_objs = {}
|
||||
for cycle in cycles_data:
|
||||
obj, _ = Cycle.objects.get_or_create(number=cycle["number"], defaults={"label": cycle["label"]})
|
||||
cycle_objs[cycle["number"]] = obj
|
||||
|
||||
# Création des niveaux et association au cycle
|
||||
levels_data = [
|
||||
{"name": "TPS", "cycle": 1},
|
||||
{"name": "PS", "cycle": 1},
|
||||
{"name": "MS", "cycle": 1},
|
||||
{"name": "GS", "cycle": 1},
|
||||
{"name": "CP", "cycle": 2},
|
||||
{"name": "CE1", "cycle": 2},
|
||||
{"name": "CE2", "cycle": 2},
|
||||
{"name": "CM1", "cycle": 3},
|
||||
{"name": "CM2", "cycle": 3},
|
||||
]
|
||||
for level in levels_data:
|
||||
Level.objects.get_or_create(
|
||||
name=level["name"],
|
||||
defaults={"cycle": cycle_objs[level["cycle"]]}
|
||||
)
|
||||
18
Back-End/Common/urls.py
Normal file
18
Back-End/Common/urls.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django.urls import path, re_path
|
||||
|
||||
from .views import (
|
||||
DomainListCreateView, DomainDetailView,
|
||||
CategoryListCreateView, CategoryDetailView,
|
||||
CompetencyListCreateView, CompetencyDetailView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^domains$', DomainListCreateView.as_view(), name="domain_list_create"),
|
||||
re_path(r'^domains/(?P<id>[0-9]+)$', DomainDetailView.as_view(), name="domain_detail"),
|
||||
|
||||
re_path(r'^categories$', CategoryListCreateView.as_view(), name="category_list_create"),
|
||||
re_path(r'^categories/(?P<id>[0-9]+)$', CategoryDetailView.as_view(), name="category_detail"),
|
||||
|
||||
re_path(r'^competencies$', CompetencyListCreateView.as_view(), name="competency_list_create"),
|
||||
re_path(r'^competencies/(?P<id>[0-9]+)$', CompetencyDetailView.as_view(), name="competency_detail"),
|
||||
]
|
||||
@ -1,3 +1,165 @@
|
||||
from django.shortcuts import render
|
||||
from django.http.response import JsonResponse
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
|
||||
from django.utils.decorators import method_decorator
|
||||
from rest_framework.parsers import JSONParser
|
||||
from rest_framework.views import APIView
|
||||
from .models import (
|
||||
Domain,
|
||||
Category,
|
||||
Competency
|
||||
)
|
||||
from .serializers import (
|
||||
DomainSerializer,
|
||||
CategorySerializer,
|
||||
CompetencySerializer
|
||||
)
|
||||
|
||||
# Create your views here.
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class DomainListCreateView(APIView):
|
||||
def get(self, request):
|
||||
domains = Domain.objects.all()
|
||||
serializer = DomainSerializer(domains, many=True)
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
|
||||
def post(self, request):
|
||||
data = JSONParser().parse(request)
|
||||
serializer = DomainSerializer(data=data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
|
||||
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class DomainDetailView(APIView):
|
||||
def get(self, request, id):
|
||||
try:
|
||||
domain = Domain.objects.get(id=id)
|
||||
serializer = DomainSerializer(domain)
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
except Domain.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def put(self, request, id):
|
||||
try:
|
||||
domain = Domain.objects.get(id=id)
|
||||
except Domain.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
data = JSONParser().parse(request)
|
||||
serializer = DomainSerializer(domain, data=data, partial=True)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def delete(self, request, id):
|
||||
try:
|
||||
domain = Domain.objects.get(id=id)
|
||||
domain.delete()
|
||||
return JsonResponse({'message': 'Deleted'}, safe=False)
|
||||
except Domain.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# Répète la même logique pour Category, Competency, EstablishmentCompetency
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class CategoryListCreateView(APIView):
|
||||
def get(self, request):
|
||||
categories = Category.objects.all()
|
||||
serializer = CategorySerializer(categories, many=True)
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
|
||||
def post(self, request):
|
||||
data = JSONParser().parse(request)
|
||||
serializer = CategorySerializer(data=data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
|
||||
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class CategoryDetailView(APIView):
|
||||
def get(self, request, id):
|
||||
try:
|
||||
category = Category.objects.get(id=id)
|
||||
serializer = CategorySerializer(category)
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
except Category.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def put(self, request, id):
|
||||
try:
|
||||
category = Category.objects.get(id=id)
|
||||
except Category.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
data = JSONParser().parse(request)
|
||||
serializer = CategorySerializer(category, data=data, partial=True)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def delete(self, request, id):
|
||||
try:
|
||||
category = Category.objects.get(id=id)
|
||||
category.delete()
|
||||
return JsonResponse({'message': 'Deleted'}, safe=False)
|
||||
except Category.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class CompetencyListCreateView(APIView):
|
||||
def get(self, request):
|
||||
cycle = request.GET.get('cycle')
|
||||
if cycle is None:
|
||||
return JsonResponse({'error': 'cycle est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
competencies_list = getAllObjects(Competency)
|
||||
competencies_list = competencies_list.filter(
|
||||
category__domain__cycle=cycle
|
||||
).distinct()
|
||||
serializer = CompetencySerializer(competencies_list, many=True)
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
|
||||
def post(self, request):
|
||||
data = JSONParser().parse(request)
|
||||
serializer = CompetencySerializer(data=data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
|
||||
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class CompetencyDetailView(APIView):
|
||||
def get(self, request, id):
|
||||
try:
|
||||
competency = Competency.objects.get(id=id)
|
||||
serializer = CompetencySerializer(competency)
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
except Competency.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def put(self, request, id):
|
||||
try:
|
||||
competency = Competency.objects.get(id=id)
|
||||
except Competency.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
data = JSONParser().parse(request)
|
||||
serializer = CompetencySerializer(competency, data=data, partial=True)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JsonResponse(serializer.data, safe=False)
|
||||
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def delete(self, request, id):
|
||||
try:
|
||||
competency = Competency.objects.get(id=id)
|
||||
competency.delete()
|
||||
return JsonResponse({'message': 'Deleted'}, safe=False)
|
||||
except Competency.DoesNotExist:
|
||||
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
Reference in New Issue
Block a user