Files
notytex/commands.py

739 lines
35 KiB
Python

import click
from flask.cli import with_appcontext
from models import db, ClassGroup, Student, StudentEnrollment, Assessment, Exercise, GradingElement, Domain, CouncilAppreciation
from datetime import date, datetime
@click.command()
@click.option('--mode', default='minimal', type=click.Choice(['minimal', 'midyear', 'demo']),
help='Type d\'initialisation : minimal (début d\'année), midyear (milieu d\'année), demo (données de démonstration)')
@with_appcontext
def init_db(mode):
"""Initialize the database with different data sets."""
db.create_all()
# Check if data already exists
if ClassGroup.query.first():
click.echo("Database already initialized!")
return
if mode == 'minimal':
init_minimal_data()
elif mode == 'midyear':
init_midyear_data()
else: # demo
init_demo_data()
def init_minimal_data():
"""Initialize database for start of school year - configuration only."""
from app_config import config_manager
# Ensure basic configuration is set
config_manager.set('context.school_year', '2025-2026')
config_manager.set('context.school_name', 'Collège')
config_manager.save()
click.echo("Database initialized for start of school year - ready to create classes and students!")
def init_midyear_data():
"""Initialize database with realistic mid-year data including temporal enrollments."""
from app_config import config_manager
from models import Grade
import random
# Set configuration
config_manager.set('context.school_year', '2024-2025')
config_manager.set('context.school_name', 'Collège Jean Moulin')
config_manager.save()
# Dates importantes pour les inscriptions temporelles
school_year_start = date(2024, 9, 1) # Début d'année scolaire
first_term_end = date(2024, 12, 20) # Fin du 1er trimestre
second_term_start = date(2025, 1, 8) # Début du 2e trimestre
today = date(2025, 2, 15) # Date actuelle (milieu 2e trimestre)
# Create 5 classes with realistic sizes
classes_data = [
("6ème A", "Classe de 6ème A", 28),
("6ème B", "Classe de 6ème B", 25),
("5ème A", "Classe de 5ème A", 30),
("5ème B", "Classe de 5ème B", 27),
("4ème A", "Classe de 4ème A", 32),
]
# French first and last names for realistic data
first_names = [
"Adrien", "Alice", "Alexandre", "Amélie", "Antoine", "Anna", "Baptiste", "Camille",
"Charlotte", "Clément", "Chloé", "David", "Emma", "Ethan", "Elise", "Enzo", "Eva",
"Fabien", "Fanny", "Gabriel", "Giulia", "Hugo", "Inès", "Jules", "Jade", "Kévin",
"Léa", "Louis", "Marie", "Mathis", "Nina", "Oscar", "Paul", "Romane", "Sophie",
"Thomas", "Valentine", "Victor", "Zoé"
]
last_names = [
"Martin", "Bernard", "Dubois", "Thomas", "Robert", "Richard", "Petit", "Durand",
"Leroy", "Moreau", "Simon", "Laurent", "Lefebvre", "Michel", "Garcia", "David",
"Bertrand", "Roux", "Vincent", "Fournier", "Morel", "Girard", "André", "Lefèvre",
"Mercier", "Dupont", "Lambert", "Bonnet", "François", "Martinez", "Rousseau",
"Garnier", "Faure", "Muller", "Henry", "Rodriguez", "Perrin"
]
classes = []
all_students = []
# Global sets to ensure uniqueness across all classes
used_names = set()
used_emails = set()
# Create classes first
for class_name, description, nb_students in classes_data:
classe = ClassGroup(name=class_name, description=description, year="2024-2025")
db.session.add(classe)
classes.append(classe)
db.session.commit()
# Create students without class assignment (temporal model)
total_students = sum(nb for _, _, nb in classes_data)
for i in range(total_students):
# Generate unique name combinations and emails
while True:
first_name = random.choice(first_names)
last_name = random.choice(last_names)
name_combo = f"{first_name}_{last_name}"
base_email = f"{first_name.lower()}.{last_name.lower()}@college.edu"
# Make email unique if needed
email = base_email
counter = 1
while email in used_emails:
email = f"{first_name.lower()}.{last_name.lower()}{counter}@college.edu"
counter += 1
if name_combo not in used_names:
used_names.add(name_combo)
used_emails.add(email)
break
student = Student(
last_name=last_name,
first_name=first_name,
email=email
# Pas de class_group_id dans le nouveau modèle temporel
)
db.session.add(student)
all_students.append(student)
db.session.commit()
# Create temporal enrollments with realistic movements
student_index = 0
movements_log = []
for i, (class_name, description, nb_students) in enumerate(classes_data):
classe = classes[i]
# Répartir les élèves pour cette classe
class_students = all_students[student_index:student_index + nb_students]
student_index += nb_students
for student in class_students:
# 90% des élèves : inscrits depuis le début d'année, toujours présents
if random.random() < 0.90:
enrollment = StudentEnrollment(
student_id=student.id,
class_group_id=classe.id,
enrollment_date=school_year_start,
departure_date=None, # Toujours inscrit
enrollment_reason="Inscription début d'année",
)
db.session.add(enrollment)
# 7% des élèves : ont quitté pendant le 1er trimestre
elif random.random() < 0.97: # 7% des 10% restants
departure_date = date(2024, random.randint(10, 11), random.randint(1, 28))
enrollment = StudentEnrollment(
student_id=student.id,
class_group_id=classe.id,
enrollment_date=school_year_start,
departure_date=departure_date,
enrollment_reason="Inscription début d'année",
departure_reason="Déménagement"
)
db.session.add(enrollment)
movements_log.append(f"Élève {student.full_name} : départ de {classe.name} le {departure_date}")
# Créer un nouvel élève pour remplacer (arrivé en janvier)
new_student = Student(
last_name=random.choice(last_names),
first_name=random.choice(first_names),
email=f"nouveau.{random.randint(1000,9999)}@college.edu"
)
db.session.add(new_student)
db.session.commit() # Pour avoir l'ID
new_enrollment = StudentEnrollment(
student_id=new_student.id,
class_group_id=classe.id,
enrollment_date=second_term_start,
departure_date=None,
enrollment_reason="Nouvel élève - arrivée en cours d'année"
)
db.session.add(new_enrollment)
movements_log.append(f"Élève {new_student.full_name} : arrivée en {classe.name} le {second_term_start}")
# 3% des élèves : arrivés en cours d'année (janvier)
else:
arrival_date = date(2025, 1, random.randint(8, 31))
enrollment = StudentEnrollment(
student_id=student.id,
class_group_id=classe.id,
enrollment_date=arrival_date,
departure_date=None,
enrollment_reason="Arrivée en cours d'année"
)
db.session.add(enrollment)
movements_log.append(f"Élève {student.full_name} : arrivée en {classe.name} le {arrival_date}")
db.session.commit()
# Get domains for realistic grading elements
domain_calcul = Domain.query.filter_by(name='Algèbre').first()
domain_geometrie = Domain.query.filter_by(name='Géométrie').first()
domain_fonctions = Domain.query.filter_by(name='Fonctions').first()
domain_stats = Domain.query.filter_by(name='Statistiques').first()
domain_problemes = Domain.query.filter_by(name='Problèmes').first()
# Create assessments for each class
assessments_templates = [
# Trimester 1 - completed assessments (4 per class)
{
"title": "Contrôle Chapitre 1 - Nombres entiers",
"description": "Évaluation sur les opérations et la divisibilité",
"trimester": 1,
"coefficient": 2.0,
"exercises": [
{
"title": "Ex1 - Opérations",
"description": "Calculs et priorités opératoires",
"elements": [
("Additions", "Calculs simples", "Calculer", 3.0, "notes", domain_calcul),
("Multiplications", "Tables et calculs", "Calculer", 4.0, "notes", domain_calcul),
("Priorités", "Parenthèses et ordres", "Calculer", 3.0, "notes", domain_calcul),
("Méthode", "Justification des étapes", "Raisonner", 2.0, "score", domain_problemes),
]
},
{
"title": "Ex2 - Divisibilité",
"description": "Critères de divisibilité et factorisation",
"elements": [
("Critères", "Divisibilité par 2,3,5,9", "Calculer", 4.0, "notes", domain_calcul),
("Division euclidienne", "Quotient et reste", "Calculer", 4.0, "notes", domain_calcul),
("Problème", "Application concrète", "Modéliser", 3.0, "score", domain_problemes),
]
}
],
"corrected": True
},
{
"title": "Évaluation Chapitre 2 - Géométrie",
"description": "Figures géométriques et mesures",
"trimester": 1,
"coefficient": 2.5,
"exercises": [
{
"title": "Ex1 - Périmètres et aires",
"description": "Calculs géométriques",
"elements": [
("Périmètre rectangle", "Formule et calcul", "Calculer", 2.0, "notes", domain_geometrie),
("Aire triangle", "Formule et application", "Calculer", 3.0, "notes", domain_geometrie),
("Construction", "Tracer au compas", "Représenter", 2.0, "score", domain_geometrie),
("Rédaction", "Présentation des calculs", "Communiquer", 2.0, "score", domain_problemes),
]
},
{
"title": "Ex2 - Problème de synthèse",
"description": "Application des formules",
"elements": [
("Modélisation", "Schéma et données", "Modéliser", 3.0, "score", domain_problemes),
("Calculs", "Périmètre et aire", "Calculer", 5.0, "notes", domain_geometrie),
("Interprétation", "Sens du résultat", "Raisonner", 2.0, "score", domain_problemes),
]
}
],
"corrected": True
},
{
"title": "Contrôle Chapitre 3 - Fractions",
"description": "Opérations sur les fractions",
"trimester": 1,
"coefficient": 3.0,
"exercises": [
{
"title": "Ex1 - Simplification",
"description": "Fractions égales et simplification",
"elements": [
("Reconnaissance", "Fractions égales", "Calculer", 2.0, "notes", domain_calcul),
("Simplification", "Réduction au plus simple", "Calculer", 4.0, "notes", domain_calcul),
("Justification", "Expliquer la méthode", "Raisonner", 2.0, "score", domain_problemes),
]
},
{
"title": "Ex2 - Opérations",
"description": "Addition et soustraction",
"elements": [
("Même dénominateur", "Calculs directs", "Calculer", 3.0, "notes", domain_calcul),
("Dénominateurs différents", "Mise au même dénominateur", "Calculer", 5.0, "notes", domain_calcul),
("Problème", "Application pratique", "Modéliser", 3.0, "score", domain_problemes),
]
}
],
"corrected": True
},
{
"title": "Devoir Maison - Recherche",
"description": "Travail de recherche et d'approfondissement",
"trimester": 1,
"coefficient": 1.5,
"exercises": [
{
"title": "Recherche documentaire",
"description": "Histoire des mathématiques",
"elements": [
("Contenu", "Richesse des informations", "Raisonner", 3.0, "score", domain_problemes),
("Sources", "Qualité et diversité", "Raisonner", 2.0, "score", domain_problemes),
("Présentation", "Mise en forme", "Communiquer", 3.0, "score", domain_problemes),
("Originalité", "Approche personnelle", "Raisonner", 2.0, "score", domain_problemes),
]
}
],
"corrected": True
},
# Trimester 2 - partially corrected assessments (2 per class)
{
"title": "Contrôle Chapitre 4 - Proportionnalité",
"description": "Tableaux de proportionnalité et applications",
"trimester": 2,
"coefficient": 2.5,
"exercises": [
{
"title": "Ex1 - Reconnaissance",
"description": "Identifier la proportionnalité",
"elements": [
("Tableaux", "Coefficients de proportionnalité", "Raisonner", 3.0, "notes", domain_calcul),
("Graphiques", "Droites passant par l'origine", "Représenter", 2.0, "score", domain_geometrie),
("Règle de trois", "Calculs simples", "Calculer", 4.0, "notes", domain_calcul),
]
},
{
"title": "Ex2 - Applications",
"description": "Problèmes de proportionnalité",
"elements": [
("Échelle", "Plans et cartes", "Modéliser", 4.0, "notes", domain_geometrie),
("Vitesse", "Distance-temps", "Modéliser", 3.0, "notes", domain_calcul),
("Pourcentages", "Calculs et applications", "Calculer", 4.0, "notes", domain_calcul),
("Méthode", "Présentation claire", "Communiquer", 2.0, "score", domain_problemes),
]
}
],
"corrected": False # Partiellement corrigé
},
{
"title": "Évaluation Chapitre 5 - Statistiques",
"description": "Moyenne, médiane, graphiques",
"trimester": 2,
"coefficient": 2.0,
"exercises": [
{
"title": "Ex1 - Calculs statistiques",
"description": "Indicateurs de position",
"elements": [
("Moyenne", "Calcul et interprétation", "Calculer", 3.0, "notes", domain_stats),
("Médiane", "Valeur centrale", "Calculer", 3.0, "notes", domain_stats),
("Étendue", "Maximum - minimum", "Calculer", 2.0, "notes", domain_stats),
]
},
{
"title": "Ex2 - Représentations",
"description": "Graphiques statistiques",
"elements": [
("Diagramme", "Construction soignée", "Représenter", 3.0, "score", domain_stats),
("Lecture", "Extraire des informations", "Raisonner", 2.0, "score", domain_stats),
("Interprétation", "Analyser les résultats", "Raisonner", 3.0, "score", domain_stats),
("Communication", "Explication claire", "Communiquer", 2.0, "score", domain_problemes),
]
}
],
"corrected": False # Non corrigé
}
]
# Create assessments for each class with temporal logic
for classe in classes:
for assessment_template in assessments_templates:
# Create assessment with realistic date
assessment_date = school_year_start
if assessment_template["trimester"] == 1:
assessment_date = date(2024, random.randint(10, 11), random.randint(1, 28))
elif assessment_template["trimester"] == 2:
assessment_date = date(2025, random.randint(1, 2), random.randint(1, 28))
assessment = Assessment(
title=assessment_template["title"],
description=assessment_template["description"],
date=assessment_date,
trimester=assessment_template["trimester"],
class_group_id=classe.id,
coefficient=assessment_template["coefficient"]
)
db.session.add(assessment)
db.session.commit()
# Create exercises and grading elements
for ex_template in assessment_template["exercises"]:
exercise = Exercise(
assessment_id=assessment.id,
title=ex_template["title"],
description=ex_template["description"],
order=assessment_template["exercises"].index(ex_template) + 1
)
db.session.add(exercise)
db.session.commit()
# Create grading elements
grading_elements = []
for element_data in ex_template["elements"]:
label, desc, skill, max_points, grading_type, domain = element_data
element = GradingElement(
exercise_id=exercise.id,
label=label,
description=desc,
skill=skill,
max_points=max_points,
grading_type=grading_type,
domain_id=domain.id if domain else None
)
db.session.add(element)
grading_elements.append(element)
db.session.commit()
# Add grades if assessment should be corrected
if assessment_template["corrected"]:
# Get students eligible for this assessment using temporal logic
from repositories.temporal_student_repository import TemporalStudentRepository
temporal_repo = TemporalStudentRepository()
eligible_students = temporal_repo.find_eligible_for_assessment(assessment)
# Generate realistic grades only for eligible students
for student in eligible_students:
for element in grading_elements:
# Generate realistic grade based on element type
if element.grading_type == "notes":
# Points: usually between 60-95% of max_points
base_ratio = random.uniform(0.6, 0.95)
grade_value = round(base_ratio * element.max_points, 1)
# Some students get perfect scores (10% chance)
if random.random() < 0.1:
grade_value = element.max_points
# Some students struggle (15% chance)
elif random.random() < 0.15:
grade_value = round(random.uniform(0.2, 0.6) * element.max_points, 1)
else: # score type (0-3)
# Competence scores: weighted towards 1 and 2
score_weights = [0.1, 0.35, 0.45, 0.1] # Probabilities for 0,1,2,3
grade_value = random.choices([0, 1, 2, 3], weights=score_weights)[0]
# Occasionally add special values (5% chance)
if random.random() < 0.05:
grade_value = random.choice([".", "d"])
grade = Grade(
student_id=student.id,
grading_element_id=element.id,
value=str(grade_value)
)
db.session.add(grade)
elif assessment_template.get("corrected") == False and random.random() < 0.4:
# Partially grade some assessments (40% of non-corrected ones get partial grades)
from repositories.temporal_student_repository import TemporalStudentRepository
temporal_repo = TemporalStudentRepository()
eligible_students = temporal_repo.find_eligible_for_assessment(assessment)
if eligible_students:
students_to_grade = random.sample(eligible_students, len(eligible_students) // 2)
for student in students_to_grade:
for element in grading_elements:
if random.random() < 0.7: # Grade 70% of elements for selected students
if element.grading_type == "notes":
base_ratio = random.uniform(0.6, 0.9)
grade_value = round(base_ratio * element.max_points, 1)
else:
grade_value = random.choices([0, 1, 2, 3], weights=[0.1, 0.3, 0.5, 0.1])[0]
grade = Grade(
student_id=student.id,
grading_element_id=element.id,
value=str(grade_value)
)
db.session.add(grade)
db.session.commit()
total_students = sum(nb for _, _, nb in classes_data)
total_assessments = len(classes) * len(assessments_templates)
# Compter les inscriptions actuelles et mouvements
total_current_students = StudentEnrollment.query.filter(StudentEnrollment.departure_date.is_(None)).count()
total_movements = len(movements_log)
click.echo(f"Database initialized for mid-year scenario with temporal enrollments:")
click.echo(f" - {len(classes)} classes with {total_students} students initially")
click.echo(f" - {total_current_students} students currently enrolled")
click.echo(f" - {total_movements} student movements simulated")
click.echo(f" - {total_assessments} assessments created with temporal logic")
click.echo(f" - 4 fully corrected assessments per class (Trimester 1)")
click.echo(f" - 2 partially corrected assessments per class (Trimester 2)")
click.echo(f"")
click.echo(f"Student movements summary:")
for movement in movements_log[:5]: # Montrer les 5 premiers mouvements
click.echo(f" - {movement}")
if len(movements_log) > 5:
click.echo(f" ... and {len(movements_log) - 5} more movements")
def init_demo_data():
"""Initialize database with simple demo data using temporal enrollment model."""
# Create sample class groups
classe_6a = ClassGroup(name="6ème A", description="Classe de 6ème A", year="2024-2025")
classe_5b = ClassGroup(name="5ème B", description="Classe de 5ème B", year="2024-2025")
db.session.add(classe_6a)
db.session.add(classe_5b)
db.session.commit()
# Create sample students (without class_group_id)
students_data = [
("Dupont", "Marie", "marie.dupont@email.com", classe_6a.id),
("Martin", "Pierre", "pierre.martin@email.com", classe_6a.id),
("Durand", "Sophie", "sophie.durand@email.com", classe_6a.id),
("Moreau", "Lucas", "lucas.moreau@email.com", classe_5b.id),
("Bernard", "Emma", "emma.bernard@email.com", classe_5b.id),
]
school_start = date(2024, 9, 1)
for last_name, first_name, email, intended_class_id in students_data:
# Create student without class assignment
student = Student(
last_name=last_name,
first_name=first_name,
email=email
# Pas de class_group_id dans le nouveau modèle temporel
)
db.session.add(student)
db.session.commit() # Pour avoir l'ID du student
# Create temporal enrollment
enrollment = StudentEnrollment(
student_id=student.id,
class_group_id=intended_class_id,
enrollment_date=school_start,
departure_date=None, # Toujours inscrit
enrollment_reason="Inscription demo"
)
db.session.add(enrollment)
db.session.commit()
# Create sample assessment
assessment = Assessment(
title="Évaluation de mathématiques",
description="Évaluation sur les fractions et les décimaux",
trimester=1,
class_group_id=classe_6a.id,
coefficient=2.0
)
db.session.add(assessment)
db.session.commit()
# Create sample exercise
exercise = Exercise(
assessment_id=assessment.id,
title="Exercice 1 - Fractions",
description="Calculs avec les fractions",
order=1
)
db.session.add(exercise)
db.session.commit()
# Récupérer des domaines existants (créés automatiquement par la configuration)
domain_calcul = Domain.query.filter_by(name='Algèbre').first()
domain_methode = Domain.query.filter_by(name='Problèmes').first()
# Create sample grading elements with domains (optionnels)
elements_data = [
("Calcul de base", "Addition et soustraction de fractions", "Calculer", 4.0, "notes", domain_calcul.id if domain_calcul else None),
("Méthode", "Justification de la méthode utilisée", "Raisonner", 2.0, "score", domain_methode.id if domain_methode else None),
("Présentation", "Clarté de la présentation", "Communiquer", 2.0, "score", None), # Pas de domaine spécifique
]
for label, description, skill, max_points, grading_type, domain_id in elements_data:
element = GradingElement(
exercise_id=exercise.id,
label=label,
description=description,
skill=skill,
max_points=max_points,
grading_type=grading_type,
domain_id=domain_id
)
db.session.add(element)
db.session.commit()
click.echo("Database initialized with demo data!")
@click.command()
@with_appcontext
def create_large_test_data():
"""Create large test data: 30 students and complex assessment."""
# Create a large class with 30 students
classe_test = ClassGroup(name="3ème Test", description="Classe de test avec 30 élèves", year="2024-2025")
db.session.add(classe_test)
db.session.commit()
# Generate 30 students with realistic French names
first_names = ["Alice", "Antoine", "Amélie", "Alexandre", "Anna", "Adrien", "Camille", "Clément", "Charlotte", "Clément",
"Emma", "Ethan", "Elise", "Enzo", "Eva", "Fabien", "Fanny", "Gabriel", "Giulia", "Hugo",
"Inès", "Jules", "Jade", "Kévin", "Léa", "Louis", "Marie", "Mathis", "Nina", "Oscar"]
last_names = ["Martin", "Bernard", "Dubois", "Thomas", "Robert", "Richard", "Petit", "Durand", "Leroy", "Moreau",
"Simon", "Laurent", "Lefebvre", "Michel", "Garcia", "David", "Bertrand", "Roux", "Vincent", "Fournier",
"Morel", "Girard", "André", "Lefèvre", "Mercier", "Dupont", "Lambert", "Bonnet", "François", "Martinez"]
for i in range(30):
student = Student(
last_name=last_names[i],
first_name=first_names[i],
email=f"{first_names[i].lower()}.{last_names[i].lower()}@test.com",
class_group_id=classe_test.id
)
db.session.add(student)
db.session.commit()
# Récupérer les domaines existants (créés automatiquement par la configuration)
domain_fonctions = Domain.query.filter_by(name='Fonctions').first()
domain_calcul = Domain.query.filter_by(name='Algèbre').first()
domain_geometrie = Domain.query.filter_by(name='Géométrie').first()
domain_stats = Domain.query.filter_by(name='Statistiques').first()
domain_problemes = Domain.query.filter_by(name='Problèmes').first()
# Create a complex assessment with 4 exercises, 5 elements each
assessment = Assessment(
title="Contrôle de Mathématiques - Fonctions et Statistiques",
description="Évaluation complète sur les fonctions affines et les statistiques descriptives",
trimester=2,
class_group_id=classe_test.id,
coefficient=3.0
)
db.session.add(assessment)
db.session.commit()
# Exercise 1: Fonctions affines
ex1 = Exercise(
assessment_id=assessment.id,
title="Ex1 - Fonctions affines",
description="Calculs et représentations graphiques",
order=1
)
db.session.add(ex1)
db.session.commit()
ex1_elements = [
("1a - Calcul image", "Calculer f(3)", "Calculer", 2.0, "notes", domain_fonctions.id if domain_fonctions else None),
("1b - Antécédent", "Résoudre f(x)=5", "Calculer", 3.0, "notes", domain_calcul.id if domain_calcul else None),
("1c - Graphique", "Tracer la droite", "Représenter", 3.0, "score", domain_fonctions.id if domain_fonctions else None),
("1d - Lecture graph", "Lire coordonnées", "Modéliser", 2.0, "notes", domain_fonctions.id if domain_fonctions else None),
("1e - Méthode", "Justification", "Raisonner", 2.0, "score", domain_problemes.id if domain_problemes else None)
]
for label, desc, skill, points, gtype, domain_id in ex1_elements:
elem = GradingElement(exercise_id=ex1.id, label=label, description=desc,
skill=skill, max_points=points, grading_type=gtype, domain_id=domain_id)
db.session.add(elem)
# Exercise 2: Équations
ex2 = Exercise(
assessment_id=assessment.id,
title="Ex2 - Équations du 1er degré",
description="Résolution d'équations",
order=2
)
db.session.add(ex2)
db.session.commit()
ex2_elements = [
("2a - Équation simple", "Résoudre 2x+3=7", "Calculer", 2.0, "notes", domain_calcul.id if domain_calcul else None),
("2b - Avec parenthèses", "3(x-1)=2x+5", "Calculer", 4.0, "notes", domain_calcul.id if domain_calcul else None),
("2c - Vérification", "Contrôler solution", "Raisonner", 1.0, "score", domain_problemes.id if domain_problemes else None),
("2d - Méthode", "Étapes de résolution", "Communiquer", 2.0, "score", domain_problemes.id if domain_problemes else None),
("2e - Application", "Problème concret", "Modéliser", 3.0, "score", domain_problemes.id if domain_problemes else None)
]
for label, desc, skill, points, gtype, domain_id in ex2_elements:
elem = GradingElement(exercise_id=ex2.id, label=label, description=desc,
skill=skill, max_points=points, grading_type=gtype, domain_id=domain_id)
db.session.add(elem)
# Exercise 3: Statistiques
ex3 = Exercise(
assessment_id=assessment.id,
title="Ex3 - Statistiques descriptives",
description="Moyennes, médianes, quartiles",
order=3
)
db.session.add(ex3)
db.session.commit()
ex3_elements = [
("3a - Moyenne", "Calculer moyenne", "Calculer", 3.0, "notes", domain_stats.id if domain_stats else None),
("3b - Médiane", "Déterminer médiane", "Calculer", 2.0, "notes", domain_stats.id if domain_stats else None),
("3c - Quartiles", "Q1 et Q3", "Calculer", 4.0, "notes", domain_stats.id if domain_stats else None),
("3d - Interprétation", "Analyser résultats", "Raisonner", 3.0, "score", domain_stats.id if domain_stats else None),
("3e - Graphique", "Diagramme en boîte", "Représenter", 2.0, "score", domain_stats.id if domain_stats else None)
]
for label, desc, skill, points, gtype, domain_id in ex3_elements:
elem = GradingElement(exercise_id=ex3.id, label=label, description=desc,
skill=skill, max_points=points, grading_type=gtype, domain_id=domain_id)
db.session.add(elem)
# Exercise 4: Problème de synthèse
ex4 = Exercise(
assessment_id=assessment.id,
title="Ex4 - Problème de synthèse",
description="Application des notions",
order=4
)
db.session.add(ex4)
db.session.commit()
ex4_elements = [
("4a - Modélisation", "Mise en équation", "Modéliser", 4.0, "score", domain_problemes.id if domain_problemes else None),
("4b - Résolution", "Calculs", "Calculer", 5.0, "notes", domain_calcul.id if domain_calcul else None),
("4c - Interprétation", "Sens du résultat", "Raisonner", 3.0, "score", domain_problemes.id if domain_problemes else None),
("4d - Communication", "Rédaction", "Communiquer", 3.0, "score", domain_problemes.id if domain_problemes else None),
("4e - Démarche", "Organisation", "Raisonner", 3.0, "score", domain_problemes.id if domain_problemes else None)
]
for label, desc, skill, points, gtype, domain_id in ex4_elements:
elem = GradingElement(exercise_id=ex4.id, label=label, description=desc,
skill=skill, max_points=points, grading_type=gtype, domain_id=domain_id)
db.session.add(elem)
db.session.commit()
click.echo(f"Created test data: {classe_test.name} with 30 students and complex assessment with 4 exercises (20 grading elements total)!")