import click from flask.cli import with_appcontext from models import db, ClassGroup, Student, Assessment, Exercise, GradingElement, Domain @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.""" 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() # 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 = [] students_by_class = [] # Global sets to ensure uniqueness across all classes used_names = set() used_emails = set() # Create classes and students for class_name, description, nb_students in classes_data: classe = ClassGroup(name=class_name, description=description, year="2024-2025") db.session.add(classe) db.session.commit() classes.append(classe) # Create students for this class class_students = [] for i in range(nb_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, class_group_id=classe.id ) db.session.add(student) class_students.append(student) students_by_class.append(class_students) 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 for i, classe in enumerate(classes): class_students = students_by_class[i] for assessment_template in assessments_templates: # Create assessment assessment = Assessment( title=assessment_template["title"], description=assessment_template["description"], 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"]: # Generate realistic grades for all students for student in class_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) students_to_grade = random.sample(class_students, len(class_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) click.echo(f"Database initialized for mid-year scenario:") click.echo(f" - {len(classes)} classes with {total_students} students total") click.echo(f" - {total_assessments} assessments created") click.echo(f" - 4 fully corrected assessments per class (Trimester 1)") click.echo(f" - 2 partially corrected assessments per class (Trimester 2)") def init_demo_data(): """Initialize database with simple demo data (original behavior).""" # 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 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), ] for last_name, first_name, email, class_group_id in students_data: student = Student( last_name=last_name, first_name=first_name, email=email, class_group_id=class_group_id ) db.session.add(student) 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)!")