739 lines
35 KiB
Python
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)!") |