From 42ef683224f7e7a6a2ac8233c5107a445061b38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Mogu=C3=A9rou?= Date: Mon, 15 Apr 2024 00:14:17 +0200 Subject: [PATCH] =?UTF-8?q?modification=20de=20la=20base=20de=20donn=C3=A9?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- colloscope/: | 204 ++++++++++++++++++ colloscope/migrations/0001_initial.py | 48 +++-- ...teur_colleur_alter_utilisateur_etudiant.py | 24 --- colloscope/models.py | 38 +++- colloscope/pdfexport.py | 47 ++-- db.sqlite3.bak | Bin 0 -> 274432 bytes 6 files changed, 304 insertions(+), 57 deletions(-) create mode 100644 colloscope/: delete mode 100644 colloscope/migrations/0002_alter_utilisateur_colleur_alter_utilisateur_etudiant.py create mode 100644 db.sqlite3.bak diff --git a/colloscope/: b/colloscope/: new file mode 100644 index 0000000..7324391 --- /dev/null +++ b/colloscope/: @@ -0,0 +1,204 @@ +from datetime import date, timedelta + +from colloscope.models import Etudiant, Critere + +from fpdf import FPDF +from fpdf.fonts import FontFace +from fpdf.enums import TableCellFillMode + +calendrier_zoneC = date(2023, 9, 18), [ + ( date(2023, 10, 21), date(2023, 11, 6) ), + ( date(2023, 12, 23), date(2024, 1, 8) ), + ( date(2024, 2, 10), date(2024, 2, 26) ), + ( date(2024, 4, 6), date(2024, 4, 22) ), +] + +def jour_of_sem(n, cal): + sem_1, vac = cal + + jour = sem_1 + (n-1) * timedelta(weeks=1) + + for (debut, fin) in vac: + if jour >= debut: + jour += 2*timedelta(weeks=1) + + return jour + +""" +etudiants = [ + ['Aboujaib', 'Alexandre', 4, 'A', '', ''], + ['Ajan', 'George', 4, 'A', '', ''], + ['Akrad', 'Lina', 1, 'SI', '', ''], + ['Aubert', 'Nicolas', 1, 'SI', '', ''], + ['Badr', 'Roman', 4, 'A', '', ''], + ['Bazire', 'Aurélien', 5, 'A', '', ''], + ['Boit', 'Arthur', 5, 'A', '', ''], + ['Boubker', 'Youssef', 5, 'A', '', ''], + ['Boudjema', 'Dylan', 1, 'SI', '', ''], + ['Chiriac', 'Mihnea', 6, 'A', '', ''], + ['Courier', 'Marine', 6, 'A', '', ''], + ['Daguin', 'Joseph', 6, 'A', '', ''], + ['Dauguen', 'Gabriel', 7, 'A', '', ''], + ['De Weer', 'Matthias', 7, 'A', '', ''], + ['Desbouis', 'Katell', 2, 'SI', '', ''], + ['Dupouy', 'Jérémie', 7, 'A', '', ''], + ['Hariri--Gautier-Picard', 'Grégoire', 8, 'A', '', ''], + ['Juricevic', 'Matteo', 8, 'A', '', ''], + ['Knanoua', 'Anas', 8, 'A', '', ''], + ['Lesenne', 'Pierrick', 9, 'A', '', ''], + ['Lin', 'Hao', 2, 'SI', '', ''], + ['Masbatin', 'Lucas', 2, 'SI', '', ''], + ['Mayuran', 'Mithushan', 9, 'A', '', ''], + ['Messahli', 'Yassine', 9, 'A', '', ''], + ['Moguérou', 'Valentin', 10, 'B', '', ''], + ['Mohellebi', 'Mathéo', 10, 'B', '', ''], + ['Mouisset--Ferrara', 'Maël', 10, 'B', '', ''], + ['Ottavi', 'Corentin', 11, 'B', '', ''], + ['Ponce', 'Alexian', 11, 'B', '', ''], + ['Pujol', 'Raphaël', 11, 'B', '', ''], + ['Pustetto', 'Mathis', 12, 'B', '', ''], + ['Radice', 'Roman', 12, 'B', '', ''], + ['Rat', 'Evelyn', 12, 'B', '', ''], + ['Rousse', 'Louis', 3, 'SI', '', ''], + ['Roux', 'Gaëtan', 3, 'SI', '', ''], + ['Rouyre--Cros', 'Célian', 3, 'SI', '', ''], + ['Sourbé', 'François-Gabriel', 13, 'B', '', ''], + ['Stourbe', 'Simon', 13, 'B', '', ''], + ['Thai', 'Dany', 13, 'B', '', ''], + ['Théodore', 'Jonathan', 14, 'B', '', ''], + ['Vandroux', 'Benoît', 14, 'B', '', ''], + ['Veyssière', 'Thibaud', 14, 'B', '', ''], + ['Vié', 'Adrien', 15, 'B', '', ''], + ['Ye', 'Luan', 15, 'B', '', ''], + ['Zarka', 'Amélie', 15, 'B', '', ''], +] +""" + +creneaux = [ + ["Mathématiques", "vendredi", "17:00", "M. OUBAHA", "C382"], + ["Anglais", "mercredi", "14:00", "Mme LE GOURIELLEC", "C393"], + ["Mathématiques", "mercredi", "15:00", "M. BOULLY", "R004"], + ["Physique", "mardi", "14:00", "Mme CHEVALIER", "R103"], + ["Mathématiques", "mardi", "18:00", "M. RAPIN", "V152"], + ["Anglais", "mardi", "14:00", "Mme BELAGGOUNE", "C4??"], + ["pas de colle", "", "", "", ""], + ["Physique", "mardi", "17:00", "M. COLIN", "C386"], + ["Mathématiques", "mercredi", "13:30", "M. BOUVEROT", "??"], + ["Anglais", "lundi", "13:00", "M. HERBAUT", "V052"], +] + +semaines = list(range(24, 34)) + +rotations = [ + # [semaine, groupe, creneau] + (24, 1, 1), + (24, 2, 2), + (24, 3, 3), + (27, 3, 3), + (28, 3, 3), + (31, 3, 3), +] + +class PDF(FPDF): + def liste_eleves(self, periode): + classe = periode.classe + etudiants = Etudiant.objects.filter(classe=classe) + + with self.table( + align="RIGHT", + col_widths=(4, 3, 1, 1, 1, 1), + width=80, + line_height=3) as table: + header = table.row() + for th in ("Nom", "Prénom", "Grp.", "TD", "LV1", "LV2"): + header.cell(th) + + for etu in etudiants: + row = table.row() + row.cell(etu.nom.upper()) # Nom + row.cell(etu.prenom) # Prénom + row.cell(etu.groupe_de_colle(periode).libelle) # Groupe + row.cell(etu.groupe_du_critere(periode, "TD")) # TD + row.cell("??") # LV1 + row.cell("??") # LV2 + + + def table_colloscope(self, creneaux, semaines, rotations): + with self.table( + align="LEFT", + width=190, + line_height=3, + col_widths=(2, 1, 1, 3, 1, *(1,)*len(semaines)), + num_heading_rows=2) as table: + + header = table.row() + for th in ("Matière", "Jour", "Heure", "Colleur", "Salle"): + header.cell(th, align="CENTER", rowspan=2) + + for sem in semaines: + header.cell(str(sem), align="CENTER") + + header2 = table.row() + for sem in semaines: + header2.cell(jour_of_sem(sem, calendrier_zoneC).strftime("%d/%m/%y"), align="CENTER") + + for i, tr in enumerate(creneaux): + matiere, jour, heure, colleur, salle = tr + + row = table.row() + row.cell(matiere) + row.cell(jour) + row.cell(heure) + row.cell(colleur) + row.cell(salle) + + for s in semaines: + for rot in rotations: + if rot[2] == i and rot[0] == s: + row.cell(str(rot[1]), align="CENTER") + break + else: + row.cell() + + def table_travaux(self): + with self.table( + align="LEFT", + width=190, + line_height=3, + col_widths=(2, 1, 1, 4, *(1,)*len(semaines)), + first_row_as_headings=False) as table: + + row = table.row() + row.cell("TP Physique") + row.cell("lundi") + row.cell("8:30") + row.cell() + + for _ in range(len(semaines)): + row.cell("9 à 15", align="CENTER") + +def generate(periode): + pdf = PDF(orientation="landscape", format="a4") + pdf.set_font("helvetica", size=6) + + pdf.set_title("Colloscope mp2i semestre 5/2") + pdf.set_author("projet colloscope") + pdf.set_author("projet colloscope") + + pdf.add_page() + pdf.cell(text="Colloscope MP2I Semestre 5/2", center=True, border=1, h=5) + base_y = pdf.t_margin + 10 + pdf.set_y(base_y) + pdf.liste_eleves(etudiants) + #pdf.set_y(base_y) + #pdf.table_colloscope(creneaux, semaines, rotations) + #pdf.y += 3 + #pdf.table_travaux() + + pdf.output("test.pdf") + +if __name__ == "__main__": + classe = Classe.get(id=1) + periode = Periode.get(classe=classe, libelle="Semestre 5/2") + + generate(periode) diff --git a/colloscope/migrations/0001_initial.py b/colloscope/migrations/0001_initial.py index 3ac3ff1..8896e3b 100644 --- a/colloscope/migrations/0001_initial.py +++ b/colloscope/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.4 on 2024-04-14 13:40 +# Generated by Django 5.0.4 on 2024-04-14 20:04 import django.db.models.deletion from django.db import migrations, models @@ -29,6 +29,13 @@ class Migration(migrations.Migration): ('nom', models.CharField(max_length=100)), ], ), + migrations.CreateModel( + name='Critere', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('libelle', models.CharField(max_length=100)), + ], + ), migrations.CreateModel( name='Lycee', fields=[ @@ -46,14 +53,6 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=20)), ], ), - migrations.CreateModel( - name='Groupe', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('libelle', models.CharField(max_length=100)), - ('classe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.classe')), - ], - ), migrations.CreateModel( name='Etudiant', fields=[ @@ -61,8 +60,10 @@ class Migration(migrations.Migration): ('prenom', models.CharField(max_length=100)), ('nom', models.CharField(max_length=100)), ('classe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.classe')), - ('groupes', models.ManyToManyField(to='colloscope.groupe')), ], + options={ + 'ordering': ['classe', 'nom', 'prenom'], + }, ), migrations.AddField( model_name='classe', @@ -79,6 +80,20 @@ class Migration(migrations.Migration): ('classe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.classe')), ], ), + migrations.CreateModel( + name='Groupe', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('libelle', models.CharField(max_length=100)), + ('critere', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='colloscope.critere')), + ('periode', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.periode')), + ], + ), + migrations.AddField( + model_name='critere', + name='periode', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.periode'), + ), migrations.CreateModel( name='Creneau', fields=[ @@ -95,6 +110,15 @@ class Migration(migrations.Migration): ('periode', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.periode')), ], ), + migrations.CreateModel( + name='Appartenance', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('etudiant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.etudiant')), + ('groupe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.groupe')), + ('periode', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.periode')), + ], + ), migrations.CreateModel( name='Rotation', fields=[ @@ -120,8 +144,8 @@ class Migration(migrations.Migration): ('username', models.CharField(max_length=100)), ('password', models.CharField(max_length=300)), ('timestamp', models.DateTimeField(auto_now_add=True)), - ('colleur', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.colleur')), - ('etudiant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.etudiant')), + ('colleur', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='colloscope.colleur')), + ('etudiant', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='colloscope.etudiant')), ], ), ] diff --git a/colloscope/migrations/0002_alter_utilisateur_colleur_alter_utilisateur_etudiant.py b/colloscope/migrations/0002_alter_utilisateur_colleur_alter_utilisateur_etudiant.py deleted file mode 100644 index 9ad315f..0000000 --- a/colloscope/migrations/0002_alter_utilisateur_colleur_alter_utilisateur_etudiant.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 5.0.4 on 2024-04-14 13:51 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('colloscope', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='utilisateur', - name='colleur', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='colloscope.colleur'), - ), - migrations.AlterField( - model_name='utilisateur', - name='etudiant', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='colloscope.etudiant'), - ), - ] diff --git a/colloscope/models.py b/colloscope/models.py index 4fa259f..f09f7f3 100644 --- a/colloscope/models.py +++ b/colloscope/models.py @@ -1,5 +1,5 @@ from django.db import models - +from django.db.models import F class Lycee(models.Model): uai = models.CharField(max_length=10) @@ -14,6 +14,7 @@ class Classe(models.Model): class Periode(models.Model): classe = models.ForeignKey(Classe, on_delete=models.CASCADE) + #critere_colle = models.ForeignKey(Critere, on_delete=models.SET_NULL, null=True) libelle = models.CharField(max_length=100) debut = models.DateField() fin = models.DateField() @@ -22,17 +23,44 @@ class Matiere(models.Model): libelle = models.CharField(max_length=100) code = models.CharField(max_length=20) +class Critere(models.Model): + periode = models.ForeignKey(Periode, on_delete=models.CASCADE) + libelle = models.CharField(max_length=100) + class Groupe(models.Model): - classe = models.ForeignKey(Classe, on_delete=models.CASCADE) + #class Meta: + # ordering=[F("periode").classe.libelle, F("periode").libelle, "libelle"] + + periode = models.ForeignKey(Periode, on_delete=models.CASCADE) + critere = models.ForeignKey(Critere, null=True, on_delete=models.CASCADE) libelle = models.CharField(max_length=100) class Etudiant(models.Model): + class Meta: + ordering=["classe", "nom", "prenom"] + classe = models.ForeignKey(Classe, on_delete=models.CASCADE) prenom = models.CharField(max_length=100) nom = models.CharField(max_length=100) #lv1 = models.ForeignKey(Matiere, on_delete=models.CASCADE) #lv2 = models.ForeignKey(Matiere, on_delete=models.CASCADE) - groupes = models.ManyToManyField(Groupe) + + def appartient(self, groupe, periode): + return Appartenance.objects.filter(periode=periode, etudiant=self, groupe=groupe).exists() + + def groupe_du_critere(self, periode, critere): + if isinstance(critere, str): + critere = Critere.objects.get(periode=periode, libelle=critere) + + return Appartenance.objects.get(periode=periode, etudiant=self, groupe__critere=critere).groupe + + def groupe_de_colle(self, periode): + return self.groupe_du_critere(periode, "colle") + +class Appartenance(models.Model): + periode = models.ForeignKey(Periode, on_delete=models.CASCADE) + etudiant = models.ForeignKey(Etudiant, on_delete=models.CASCADE) + groupe = models.ForeignKey(Groupe, on_delete=models.CASCADE) class Colleur(models.Model): civilite = models.CharField(max_length=1) @@ -65,5 +93,5 @@ class Utilisateur(models.Model): username = models.CharField(max_length=100) password = models.CharField(max_length=300) timestamp = models.DateTimeField(auto_now_add=True) - etudiant = models.ForeignKey(Etudiant, on_delete=models.DO_NOTHING, null=True) - colleur = models.ForeignKey(Colleur, on_delete=models.DO_NOTHING, null=True) + etudiant = models.ForeignKey(Etudiant, on_delete=models.SET_NULL, null=True) + colleur = models.ForeignKey(Colleur, on_delete=models.SET_NULL, null=True) diff --git a/colloscope/pdfexport.py b/colloscope/pdfexport.py index b286c46..087f29e 100644 --- a/colloscope/pdfexport.py +++ b/colloscope/pdfexport.py @@ -1,5 +1,7 @@ from datetime import date, timedelta +from colloscope.models import Etudiant, Critere, Classe + from fpdf import FPDF from fpdf.fonts import FontFace from fpdf.enums import TableCellFillMode @@ -22,6 +24,7 @@ def jour_of_sem(n, cal): return jour +""" etudiants = [ ['Aboujaib', 'Alexandre', 4, 'A', '', ''], ['Ajan', 'George', 4, 'A', '', ''], @@ -69,6 +72,7 @@ etudiants = [ ['Ye', 'Luan', 15, 'B', '', ''], ['Zarka', 'Amélie', 15, 'B', '', ''], ] +""" creneaux = [ ["Mathématiques", "vendredi", "17:00", "M. OUBAHA", "C382"], @@ -96,7 +100,10 @@ rotations = [ ] class PDF(FPDF): - def liste_eleves(self, etudiants): + def liste_eleves(self, periode): + classe = periode.classe + etudiants = Etudiant.objects.filter(classe=classe) + with self.table( align="RIGHT", col_widths=(4, 3, 1, 1, 1, 1), @@ -108,12 +115,13 @@ class PDF(FPDF): for etu in etudiants: row = table.row() - row.cell(etu[0].upper()) # Nom - row.cell(etu[1]) # Prénom - row.cell(str(etu[2])) # Groupe - row.cell(etu[3]) # TD - row.cell(etu[4]) # LV1 - row.cell(etu[5]) # LV2 + row.cell(etu.nom.upper()) # Nom + row.cell(etu.prenom) # Prénom + row.cell(etu.groupe_de_colle(periode).libelle) # Groupe + row.cell("??") + #row.cell(etu.groupe_du_critere(periode, "TD")) # TD + row.cell("??") # LV1 + row.cell("??") # LV2 def table_colloscope(self, creneaux, semaines, rotations): @@ -170,25 +178,32 @@ class PDF(FPDF): for _ in range(len(semaines)): row.cell("9 à 15", align="CENTER") -def generate(): +def generate(periode): + classe = periode.classe + pdf = PDF(orientation="landscape", format="a4") pdf.set_font("helvetica", size=6) - pdf.set_title("colloscope mp2i semestre 5/2") + titre = f"Colloscope {classe.libelle} {periode.libelle}" + + pdf.set_title(titre) pdf.set_author("projet colloscope") pdf.set_author("projet colloscope") pdf.add_page() - pdf.cell(text="Colloscope MP2I Semestre 5/2", center=True, border=1, h=5) + pdf.cell(text=titre, center=True, border=1, h=5) base_y = pdf.t_margin + 10 pdf.set_y(base_y) - pdf.liste_eleves(etudiants) - pdf.set_y(base_y) - pdf.table_colloscope(creneaux, semaines, rotations) - pdf.y += 3 - pdf.table_travaux() + pdf.liste_eleves(periode) + #pdf.set_y(base_y) + #pdf.table_colloscope(creneaux, semaines, rotations) + #pdf.y += 3 + #pdf.table_travaux() pdf.output("test.pdf") if __name__ == "__main__": - generate() + classe = Classe.objects.get(id=1) + periode = Periode.objects.get(classe=classe, libelle="Semestre 5/2") + + generate(periode) diff --git a/db.sqlite3.bak b/db.sqlite3.bak new file mode 100644 index 0000000000000000000000000000000000000000..726e9262f0932111ff841645b6318ed7faee2fc3 GIT binary patch literal 274432 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�&9DfG&v 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 N0T2KI5ctIq`2X~JK`#IR literal 0 HcmV?d00001