From b219f1248fa84eb2b015a5a04f80905dad8904ae Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 17 Nov 2017 16:11:55 +0100 Subject: Page principale de l’emploi du temps des salles --- views.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'views.py') diff --git a/views.py b/views.py index c647fac..c008052 100644 --- a/views.py +++ b/views.py @@ -96,5 +96,8 @@ def calendars(request, year_slug, timetable_slug, group_slug): return render(request, "calendars.html", {"group": group, "groups": groups}) +def rooms(request): + return render(request, "index.html") + def ctx_processor(request): return {"celcatsanitizer_version": edt.VERSION} -- cgit v1.2.1 From 959afb011f5e98e56f88a455228eab32579c9433 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 18 Nov 2017 13:35:37 +0100 Subject: Contenu de la page des emplois du temps --- views.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index c008052..9047329 100644 --- a/views.py +++ b/views.py @@ -15,12 +15,12 @@ import datetime -from django.db.models import Max -from django.db.models.functions import Length +from django.db.models import Count, Max +from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render -from .models import Timetable, Group, Course, Year +from .models import Course, Group, Room, Timetable, Year from .utils import get_current_week, get_current_or_next_week, get_week, group_courses import edt @@ -97,7 +97,36 @@ def calendars(request, year_slug, timetable_slug, group_slug): return render(request, "calendars.html", {"group": group, "groups": groups}) def rooms(request): - return render(request, "index.html") + # On récupère les dates allant de cette semaine à dans un mois + start, _ = get_week(*get_current_week()) + end = start + datetime.timedelta(weeks=4) + + # Récupération des salles et de toutes les semaines où elles sont + # concernées + # Cette requête est un peu lente sur sqlite… j’espère que ce sera mieux + # sur la base de prod. + rooms = Room.objects.filter(course__begin__gte=start, course__begin__lt=end) \ + .annotate(year=ExtractYear("course__begin"), + week=ExtractWeek("course__begin")) \ + .order_by("name").annotate(c=Count("*")) + + rooms_weeks = [] + for room in rooms: + if len(rooms_weeks) == 0 or rooms_weeks[-1].id != room.id: + room.weeks = [] + rooms_weeks.append(room) + + date, _ = get_week(room.year, room.week) + rooms_weeks[-1].weeks.append(date) + + return render(request, "group_list.html", {"groups": rooms_weeks}) + +def room_timetable(request, room_slug): + room = get_object_or_404(Room, slug=room_slug) + courses = Course.objects.filter(rooms__in=(room,)).order_by("begin") + + return render(request, "timetable.html", {"group": room, "courser": courses, + }) def ctx_processor(request): return {"celcatsanitizer_version": edt.VERSION} -- cgit v1.2.1 From 599ca85167ad7d53f6434b105cb74c761d994ecf Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 18 Nov 2017 16:04:18 +0100 Subject: Liens et URLs pour les emplois du temps des salles --- views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 9047329..e35796b 100644 --- a/views.py +++ b/views.py @@ -121,7 +121,7 @@ def rooms(request): return render(request, "group_list.html", {"groups": rooms_weeks}) -def room_timetable(request, room_slug): +def room_timetable(request, room_slug, year=None, week=None): room = get_object_or_404(Room, slug=room_slug) courses = Course.objects.filter(rooms__in=(room,)).order_by("begin") -- cgit v1.2.1 From 1046a9ea68d9a29dc929eb88581e50a0704a5142 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 18 Nov 2017 16:04:28 +0100 Subject: Optimisation (?) de la requête des emplois du temps des salles --- views.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index e35796b..3916fac 100644 --- a/views.py +++ b/views.py @@ -103,12 +103,13 @@ def rooms(request): # Récupération des salles et de toutes les semaines où elles sont # concernées - # Cette requête est un peu lente sur sqlite… j’espère que ce sera mieux - # sur la base de prod. + # Cette requête est un peu lente sur sqlite… + # Par contre c’est beaucoup plus rapide sur PostgreSQL rooms = Room.objects.filter(course__begin__gte=start, course__begin__lt=end) \ + .order_by("name") \ .annotate(year=ExtractYear("course__begin"), - week=ExtractWeek("course__begin")) \ - .order_by("name").annotate(c=Count("*")) + week=ExtractWeek("course__begin"), + c=Count("*")) rooms_weeks = [] for room in rooms: -- cgit v1.2.1 From 3148aaf7c43866bd672d54ac54a0e70bc71f1020 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 18 Nov 2017 17:14:26 +0100 Subject: Mise en commun du traitement des données avant rendu de l’emploi du temps --- views.py | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index 3916fac..428711f 100644 --- a/views.py +++ b/views.py @@ -61,7 +61,7 @@ def group_list(request, year_slug, timetable_slug): return render(request, "group_list.html", {"timetable": timetable, "groups": groups}) -def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): +def timetable_common(request, obj, year=None, week=None): current_year, current_week = get_current_or_next_week() is_old_timetable, provided_week = False, True @@ -73,21 +73,30 @@ def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=No start, end = get_week(year, week) - timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - group = get_object_or_404(Group, slug=group_slug, timetable=timetable) - - courses = Course.objects.get_courses_for_group(group, begin__gte=start, begin__lt=end) + courses = Course.objects.get_courses(obj, begin__gte=start, begin__lt=end) if not courses.exists() and provided_week: raise Http404 last_update = courses.aggregate(Max("last_update"))["last_update__max"] grouped_courses = group_courses(courses) - return render(request, "timetable.html", {"group": group, "courses": grouped_courses, + return render(request, "timetable.html", {"group": obj, "courses": grouped_courses, "last_update": last_update, "year": year, "week": int(week), "is_old_timetable": is_old_timetable}) +def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): + timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) + group = get_object_or_404(Group, slug=group_slug, timetable=timetable) + + if Group.objects.filter(timetable=timetable, mention=group.mention, + subgroup__startswith=group.subgroup).count() > 1: + subgroups = Group.objects.get_relevant_groups(timetable, mention=group.mention, + subgroup__startswith=group.subgroup) + return group_list_common(request, timetable, subgroups) + + return timetable_common(request, group, year, week) + def calendars(request, year_slug, timetable_slug, group_slug): group = get_object_or_404(Group, timetable__year__slug=year_slug, timetable__slug=timetable_slug, slug=group_slug) @@ -102,32 +111,40 @@ def rooms(request): end = start + datetime.timedelta(weeks=4) # Récupération des salles et de toutes les semaines où elles sont - # concernées - # Cette requête est un peu lente sur sqlite… - # Par contre c’est beaucoup plus rapide sur PostgreSQL + # concernées. + # Cette requête associe chaque salle à toutes les semaines où un + # cours s’y déroule. Le résultat est trié par le nom de la salle + # et par semaine. + # TODO optimiser cette requête, elle me semble un peu lente rooms = Room.objects.filter(course__begin__gte=start, course__begin__lt=end) \ .order_by("name") \ .annotate(year=ExtractYear("course__begin"), week=ExtractWeek("course__begin"), c=Count("*")) + # Regroupement des semaines dans une liste de chaque objet salle rooms_weeks = [] for room in rooms: + # Si on a pas traité de salle ou que la salle courante + # dans le résultat de la requête est différente de la dernière + # dans la liste des salles traitées if len(rooms_weeks) == 0 or rooms_weeks[-1].id != room.id: + # On lui affecte un tableau et on l’ajoute dans + # la liste des salles à traiter room.weeks = [] rooms_weeks.append(room) + # On récupère le premier jour de la semaine date, _ = get_week(room.year, room.week) + # Et on le rajoute dans la liste des semaines de la salle. rooms_weeks[-1].weeks.append(date) + # Rendu de la page. return render(request, "group_list.html", {"groups": rooms_weeks}) def room_timetable(request, room_slug, year=None, week=None): room = get_object_or_404(Room, slug=room_slug) - courses = Course.objects.filter(rooms__in=(room,)).order_by("begin") - - return render(request, "timetable.html", {"group": room, "courser": courses, - }) + return timetable_common(request, room, year, week) def ctx_processor(request): return {"celcatsanitizer_version": edt.VERSION} -- cgit v1.2.1 From bb049a8d5954bbcf3ae5207a0ab4445591555d6e Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 18 Nov 2017 18:21:52 +0100 Subject: Tentative de mise en commun de la template des edts --- views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 428711f..cb6978b 100644 --- a/views.py +++ b/views.py @@ -83,7 +83,8 @@ def timetable_common(request, obj, year=None, week=None): return render(request, "timetable.html", {"group": obj, "courses": grouped_courses, "last_update": last_update, "year": year, "week": int(week), - "is_old_timetable": is_old_timetable}) + "is_old_timetable": is_old_timetable, + "group_mode": isinstance(obj, Group)}) def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) -- cgit v1.2.1 From e1c4eea3c706bb45cd73416e2e8626bd50a97cfb Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Mon, 27 Nov 2017 16:04:27 +0100 Subject: Correction des interfaces utilisateur --- views.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index cb6978b..3179ec5 100644 --- a/views.py +++ b/views.py @@ -37,7 +37,7 @@ def mention_list(request, year_slug): def group_list(request, year_slug, timetable_slug): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - groups = Group.objects.filter(timetable=timetable, hidden=False).order_by("name") + groups = Group.objects.filter(timetable=timetable.source, hidden=False).order_by("name") start, _ = get_week(*get_current_week()) end = start + datetime.timedelta(weeks=4) @@ -61,7 +61,7 @@ def group_list(request, year_slug, timetable_slug): return render(request, "group_list.html", {"timetable": timetable, "groups": groups}) -def timetable_common(request, obj, year=None, week=None): +def timetable_common(request, obj, year=None, week=None, timetable=None): current_year, current_week = get_current_or_next_week() is_old_timetable, provided_week = False, True @@ -84,27 +84,24 @@ def timetable_common(request, obj, year=None, week=None): "last_update": last_update, "year": year, "week": int(week), "is_old_timetable": is_old_timetable, - "group_mode": isinstance(obj, Group)}) + "group_mode": isinstance(obj, Group), + "timetable": timetable}) def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - group = get_object_or_404(Group, slug=group_slug, timetable=timetable) + group = get_object_or_404(Group, slug=group_slug, timetable=timetable.source) - if Group.objects.filter(timetable=timetable, mention=group.mention, - subgroup__startswith=group.subgroup).count() > 1: - subgroups = Group.objects.get_relevant_groups(timetable, mention=group.mention, - subgroup__startswith=group.subgroup) - return group_list_common(request, timetable, subgroups) - - return timetable_common(request, group, year, week) + return timetable_common(request, group, year, week, timetable) def calendars(request, year_slug, timetable_slug, group_slug): - group = get_object_or_404(Group, timetable__year__slug=year_slug, - timetable__slug=timetable_slug, slug=group_slug) + timetable = get_object_or_404(Timetable, year__slug=year_slug, + slug=timetable_slug) + group = get_object_or_404(Group, timetable=timetable.source, slug=group_slug) groups = Group.objects.get_parents(group).annotate(length=Length("subgroup")) \ .order_by("length") - return render(request, "calendars.html", {"group": group, "groups": groups}) + return render(request, "calendars.html", {"timetable": timetable, + "group": group, "groups": groups}) def rooms(request): # On récupère les dates allant de cette semaine à dans un mois -- cgit v1.2.1 From 5d4d7530e1aba199c2604b311b17bef253f0a008 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Mon, 27 Nov 2017 16:27:50 +0100 Subject: Remplacement des références aux champs timetable vers source --- views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index 3179ec5..2bf596b 100644 --- a/views.py +++ b/views.py @@ -37,7 +37,7 @@ def mention_list(request, year_slug): def group_list(request, year_slug, timetable_slug): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - groups = Group.objects.filter(timetable=timetable.source, hidden=False).order_by("name") + groups = Group.objects.filter(source=timetable.source, hidden=False).order_by("name") start, _ = get_week(*get_current_week()) end = start + datetime.timedelta(weeks=4) @@ -89,14 +89,14 @@ def timetable_common(request, obj, year=None, week=None, timetable=None): def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - group = get_object_or_404(Group, slug=group_slug, timetable=timetable.source) + group = get_object_or_404(Group, slug=group_slug, source=timetable.source) return timetable_common(request, group, year, week, timetable) def calendars(request, year_slug, timetable_slug, group_slug): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - group = get_object_or_404(Group, timetable=timetable.source, slug=group_slug) + group = get_object_or_404(Group, source=timetable.source, slug=group_slug) groups = Group.objects.get_parents(group).annotate(length=Length("subgroup")) \ .order_by("length") -- cgit v1.2.1 From fb6ea65e7d32dcf3d697e6c63985a018ada4d6b1 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Mon, 27 Nov 2017 16:37:31 +0100 Subject: Ajout d’un gestionnaire pour Timetable récupérant automatiquement les années Réduit considérablement le nombre d’appels effectués dans l’interface d’administration --- views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 2bf596b..97a1d28 100644 --- a/views.py +++ b/views.py @@ -31,7 +31,7 @@ def index(request): def mention_list(request, year_slug): year = get_object_or_404(Year, slug=year_slug) - timetables = Timetable.objects.order_by("name").filter(year=year).select_related("year") + timetables = Timetable.objects.order_by("name").filter(year=year) return render(request, "index.html", {"year": year, "elements": timetables}) -- cgit v1.2.1 From a2fcd4c7c42b6c02ff8ff7dac4aa23b3d17407de Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Wed, 17 Jan 2018 12:34:11 +0100 Subject: Base du formulaire de QSJPS --- views.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 97a1d28..e8fc259 100644 --- a/views.py +++ b/views.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017 Alban Gruin +# Copyright (C) 2017-2018 Alban Gruin # # celcatsanitizer is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published @@ -19,7 +19,9 @@ from django.db.models import Count, Max from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render +from django.views.decorators.csrf import csrf_exempt +from .forms import QSJPSForm from .models import Course, Group, Room, Timetable, Year from .utils import get_current_week, get_current_or_next_week, get_week, group_courses @@ -144,5 +146,21 @@ def room_timetable(request, room_slug, year=None, week=None): room = get_object_or_404(Room, slug=room_slug) return timetable_common(request, room, year, week) +@csrf_exempt +def qsjps(request): + if request.method == "POST": + # Si on traite un formulaire, on le valide + form = QSJPSForm(request.POST) + if form.is_valid(): + # Formulaire validé + return None + else: + # Formulaire invalide, on le raffiche avec une erreur + return render(request, "form_qsjps.html", {"form": form}) + else: + # Sinon, affichage d’un formulaire vide + form = QSJPSForm() + return render(request, "form_qsjps.html", {"form": form}) + def ctx_processor(request): return {"celcatsanitizer_version": edt.VERSION} -- cgit v1.2.1 From b1e5d205e37a2c0a5d4f42afe0bdce9e0fbf97dd Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Thu, 18 Jan 2018 12:06:45 +0100 Subject: Modification de la gestion du formulaire qsjps Renommage de la template contenant le formulaire --- views.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index e8fc259..1c82b03 100644 --- a/views.py +++ b/views.py @@ -154,13 +154,14 @@ def qsjps(request): if form.is_valid(): # Formulaire validé return None - else: - # Formulaire invalide, on le raffiche avec une erreur - return render(request, "form_qsjps.html", {"form": form}) + # Si le formulaire est invalide, on ré-affiche le formulaire + # avec les erreurs else: - # Sinon, affichage d’un formulaire vide + # Si le formulaire n’a pas été soumis, on en instancie un + # nouveau form = QSJPSForm() - return render(request, "form_qsjps.html", {"form": form}) + + return render(request, "qsjps_form.html", {"form": form}) def ctx_processor(request): return {"celcatsanitizer_version": edt.VERSION} -- cgit v1.2.1 From 175e1c1139a77a02f3c52d77a4d2b118c2b2e578 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Thu, 18 Jan 2018 12:17:08 +0100 Subject: Ajout d’une template pour lister les salles trouvées --- views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 1c82b03..0231c9e 100644 --- a/views.py +++ b/views.py @@ -153,7 +153,7 @@ def qsjps(request): form = QSJPSForm(request.POST) if form.is_valid(): # Formulaire validé - return None + return render(request, "qsjps.html", {"rooms": [], "form": form}) # Si le formulaire est invalide, on ré-affiche le formulaire # avec les erreurs else: -- cgit v1.2.1 From d7dfa0c001a9b84541e1545e45d0536a87d6880e Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 19 Jan 2018 19:20:21 +0100 Subject: Liens permettant de naviguer sur les pages des semaines suivantes et précédentes --- views.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'views.py') diff --git a/views.py b/views.py index 0231c9e..10dcfa2 100644 --- a/views.py +++ b/views.py @@ -79,12 +79,19 @@ def timetable_common(request, obj, year=None, week=None, timetable=None): if not courses.exists() and provided_week: raise Http404 + # Récupération des semaines suivantes et précédentes pour les + # afficher proprement dans l’emploi du temps + last_week = getattr(Course.objects.get_courses(obj, begin__lt=start).last(), "begin", None) + next_week = getattr(Course.objects.get_courses(obj, begin__gte=end).first(), "begin", None) + last_update = courses.aggregate(Max("last_update"))["last_update__max"] grouped_courses = group_courses(courses) return render(request, "timetable.html", {"group": obj, "courses": grouped_courses, "last_update": last_update, "year": year, "week": int(week), + "last_week": last_week, + "next_week": next_week, "is_old_timetable": is_old_timetable, "group_mode": isinstance(obj, Group), "timetable": timetable}) -- cgit v1.2.1 From a0101b9a7566b5296c3490ce3592984976553807 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 20 Jan 2018 22:28:21 +0100 Subject: On cache les groupes qui n’ont plus de cours La requête est assez longue à s’effectuer sur SQLite, mais pas sur PostgreSQL --- views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index 10dcfa2..9b53f3a 100644 --- a/views.py +++ b/views.py @@ -15,7 +15,7 @@ import datetime -from django.db.models import Count, Max +from django.db.models import Max from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render @@ -39,11 +39,11 @@ def mention_list(request, year_slug): def group_list(request, year_slug, timetable_slug): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - groups = Group.objects.filter(source=timetable.source, hidden=False).order_by("name") start, _ = get_week(*get_current_week()) end = start + datetime.timedelta(weeks=4) + groups = Group.objects.get_relevant_groups(start, source=timetable.source, hidden=False) groups_weeks = Course.objects.get_weeks(begin__gte=start, begin__lt=end, groups__in=groups) for group in groups: -- cgit v1.2.1 From 6f4822291d89dadcb6bae94c897e89e309218e7e Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 21 Jan 2018 19:35:25 +0100 Subject: Correction d’une erreur d’importation --- views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 9b53f3a..842a02e 100644 --- a/views.py +++ b/views.py @@ -15,7 +15,7 @@ import datetime -from django.db.models import Max +from django.db.models import Count, Max from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render -- cgit v1.2.1 From ee94b9e48dc2b632f876702df57136f394ee5574 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 27 Jan 2018 19:57:02 +0100 Subject: Requête de QSJPS Pour chaque salle, on compte tous les cours commençant avant la fin de l’intervalle entré par l’utilisateur et finissant après le début de cet intervalle. Tous les cours correspondant à cette requête se trouvent au moins en partie sur l’intervalle. On sélectionne ensuite les salles n’ayant pas de cours correspondant à la requête précédente. --- views.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 0231c9e..e79de47 100644 --- a/views.py +++ b/views.py @@ -19,6 +19,7 @@ from django.db.models import Count, Max from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render +from django.utils import timezone from django.views.decorators.csrf import csrf_exempt from .forms import QSJPSForm @@ -153,7 +154,18 @@ def qsjps(request): form = QSJPSForm(request.POST) if form.is_valid(): # Formulaire validé - return render(request, "qsjps.html", {"rooms": [], "form": form}) + day = form.cleaned_data["day"] + begin_hour = form.cleaned_data["begin"] + end_hour = form.cleaned_data["end"] + + begin = timezone.make_aware(datetime.datetime.combine(day, + begin_hour)) + end = timezone.make_aware(datetime.datetime.combine(day, end_hour)) + + rooms = Room.objects.qsjps(begin, end) + return render(request, "qsjps.html", {"rooms": rooms, + "form": form}) + # Si le formulaire est invalide, on ré-affiche le formulaire # avec les erreurs else: -- cgit v1.2.1 From 7c73c8f900b86ebd58f48171cbd5284c29bdf840 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 27 Jan 2018 23:34:14 +0100 Subject: PEP8 sur views.py --- views.py | 62 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 21 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index e79de47..94de177 100644 --- a/views.py +++ b/views.py @@ -24,28 +24,36 @@ from django.views.decorators.csrf import csrf_exempt from .forms import QSJPSForm from .models import Course, Group, Room, Timetable, Year -from .utils import get_current_week, get_current_or_next_week, get_week, group_courses +from .utils import get_current_week, get_current_or_next_week, get_week, \ + group_courses import edt + def index(request): years = Year.objects.order_by("name") return render(request, "index.html", {"elements": years}) + def mention_list(request, year_slug): year = get_object_or_404(Year, slug=year_slug) timetables = Timetable.objects.order_by("name").filter(year=year) - return render(request, "index.html", {"year": year, "elements": timetables}) + return render(request, "index.html", + {"year": year, "elements": timetables}) + def group_list(request, year_slug, timetable_slug): - timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) - groups = Group.objects.filter(source=timetable.source, hidden=False).order_by("name") + timetable = get_object_or_404(Timetable, year__slug=year_slug, + slug=timetable_slug) + groups = Group.objects.filter(source=timetable.source, hidden=False) \ + .order_by("name") start, _ = get_week(*get_current_week()) end = start + datetime.timedelta(weeks=4) - groups_weeks = Course.objects.get_weeks(begin__gte=start, begin__lt=end, groups__in=groups) + groups_weeks = Course.objects.get_weeks(begin__gte=start, begin__lt=end, + groups__in=groups) for group in groups: for group_week in groups_weeks: @@ -62,7 +70,9 @@ def group_list(request, year_slug, timetable_slug): if hasattr(group, "weeks"): group.weeks.sort() - return render(request, "group_list.html", {"timetable": timetable, "groups": groups}) + return render(request, "group_list.html", + {"timetable": timetable, "groups": groups}) + def timetable_common(request, obj, year=None, week=None, timetable=None): current_year, current_week = get_current_or_next_week() @@ -83,28 +93,34 @@ def timetable_common(request, obj, year=None, week=None, timetable=None): last_update = courses.aggregate(Max("last_update"))["last_update__max"] grouped_courses = group_courses(courses) - return render(request, "timetable.html", {"group": obj, "courses": grouped_courses, - "last_update": last_update, - "year": year, "week": int(week), - "is_old_timetable": is_old_timetable, - "group_mode": isinstance(obj, Group), - "timetable": timetable}) + return render(request, "timetable.html", + {"group": obj, "courses": grouped_courses, + "last_update": last_update, "year": year, "week": int(week), + "is_old_timetable": is_old_timetable, + "group_mode": isinstance(obj, Group), + "timetable": timetable}) + -def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): - timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) +def timetable(request, year_slug, timetable_slug, group_slug, + year=None, week=None): + timetable = get_object_or_404(Timetable, year__slug=year_slug, + slug=timetable_slug) group = get_object_or_404(Group, slug=group_slug, source=timetable.source) return timetable_common(request, group, year, week, timetable) + def calendars(request, year_slug, timetable_slug, group_slug): timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) group = get_object_or_404(Group, source=timetable.source, slug=group_slug) - groups = Group.objects.get_parents(group).annotate(length=Length("subgroup")) \ - .order_by("length") + groups = Group.objects.get_parents(group) \ + .annotate(length=Length("subgroup")) \ + .order_by("length") + + return render(request, "calendars.html", + {"timetable": timetable, "group": group, "groups": groups}) - return render(request, "calendars.html", {"timetable": timetable, - "group": group, "groups": groups}) def rooms(request): # On récupère les dates allant de cette semaine à dans un mois @@ -117,7 +133,8 @@ def rooms(request): # cours s’y déroule. Le résultat est trié par le nom de la salle # et par semaine. # TODO optimiser cette requête, elle me semble un peu lente - rooms = Room.objects.filter(course__begin__gte=start, course__begin__lt=end) \ + rooms = Room.objects.filter(course__begin__gte=start, + course__begin__lt=end) \ .order_by("name") \ .annotate(year=ExtractYear("course__begin"), week=ExtractWeek("course__begin"), @@ -143,10 +160,12 @@ def rooms(request): # Rendu de la page. return render(request, "group_list.html", {"groups": rooms_weeks}) + def room_timetable(request, room_slug, year=None, week=None): room = get_object_or_404(Room, slug=room_slug) return timetable_common(request, room, year, week) + @csrf_exempt def qsjps(request): if request.method == "POST": @@ -163,8 +182,8 @@ def qsjps(request): end = timezone.make_aware(datetime.datetime.combine(day, end_hour)) rooms = Room.objects.qsjps(begin, end) - return render(request, "qsjps.html", {"rooms": rooms, - "form": form}) + return render(request, "qsjps.html", + {"rooms": rooms, "form": form}) # Si le formulaire est invalide, on ré-affiche le formulaire # avec les erreurs @@ -175,5 +194,6 @@ def qsjps(request): return render(request, "qsjps_form.html", {"form": form}) + def ctx_processor(request): return {"celcatsanitizer_version": edt.VERSION} -- cgit v1.2.1 From 7f575d53d17df6f1e6ade6e0bf6c06049c5a21ef Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 28 Jan 2018 21:16:42 +0100 Subject: Requête de liste des salles optimisée pour PostgreSQL --- views.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'views.py') diff --git a/views.py b/views.py index 842a02e..5ce9816 100644 --- a/views.py +++ b/views.py @@ -15,7 +15,10 @@ import datetime +from django.contrib.postgres.aggregates import ArrayAgg +from django.db import connection from django.db.models import Count, Max +from django.db.models.expressions import RawSQL from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render @@ -117,6 +120,24 @@ def rooms(request): start, _ = get_week(*get_current_week()) end = start + datetime.timedelta(weeks=4) + if connection.vendor == "postgresql": + # Si le SGBD est PostgreSQL, on utilise une requête à base de + # ArrayAgg. Elle présente l’avantage d’être plus rapide que la + # requête « généraliste » et de ne pas nécessiter de + # traitement après. On récupère chaque salle ayant un cours + # dans le mois à venir. Pour chacun de ses cours, on ne + # récupère que le premier jour de la semaine, et si jamais ce + # jour n’est pas déjà dans la liste des semaines de cours + # (« weeks »), on l’y rajoute. + rooms = Room.objects.filter(course__begin__gte=start, + course__begin__lt=end) \ + .order_by("name") \ + .annotate(weeks=ArrayAgg( + RawSQL("date_trunc('week', edt_course.begin)", + []), distinct=True)) + + return render(request, "group_list.html", {"groups": rooms}) + # Récupération des salles et de toutes les semaines où elles sont # concernées. # Cette requête associe chaque salle à toutes les semaines où un -- cgit v1.2.1 From 3f2b67605dea039c9498a1c67a89ef6d5443e0a9 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Tue, 3 Apr 2018 10:51:19 +0200 Subject: On importe ArrayAgg que lorsqu’on utilise une base postgres --- views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index 5ce9816..c3bcdc2 100644 --- a/views.py +++ b/views.py @@ -15,7 +15,6 @@ import datetime -from django.contrib.postgres.aggregates import ArrayAgg from django.db import connection from django.db.models import Count, Max from django.db.models.expressions import RawSQL @@ -30,6 +29,9 @@ from .utils import get_current_week, get_current_or_next_week, get_week, group_c import edt +if connection.vendor == "postgresql": + from django.contrib.postgres.aggregates import ArrayAgg + def index(request): years = Year.objects.order_by("name") return render(request, "index.html", {"elements": years}) -- cgit v1.2.1 From 4efb7fb7e716788ff65fea74cba60e211b4944eb Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 15 Apr 2018 11:39:04 +0200 Subject: On importe RawSQL que lorsqu’on utilise PostgreSQL --- views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index c3bcdc2..2a500c1 100644 --- a/views.py +++ b/views.py @@ -17,7 +17,6 @@ import datetime from django.db import connection from django.db.models import Count, Max -from django.db.models.expressions import RawSQL from django.db.models.functions import ExtractWeek, ExtractYear, Length from django.http import Http404 from django.shortcuts import get_object_or_404, render @@ -31,6 +30,7 @@ import edt if connection.vendor == "postgresql": from django.contrib.postgres.aggregates import ArrayAgg + from django.db.models.expressions import RawSQL def index(request): years = Year.objects.order_by("name") -- cgit v1.2.1 From 1934cdb6093a96269dc3ea911776825768fe5ae7 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 15 Apr 2018 15:25:16 +0200 Subject: Légères corrections PEP8 --- views.py | 1 + 1 file changed, 1 insertion(+) (limited to 'views.py') diff --git a/views.py b/views.py index bdbbdc2..de510a3 100644 --- a/views.py +++ b/views.py @@ -34,6 +34,7 @@ if connection.vendor == "postgresql": from django.contrib.postgres.aggregates import ArrayAgg from django.db.models.expressions import RawSQL + def index(request): years = Year.objects.order_by("name") return render(request, "index.html", {"elements": years}) -- cgit v1.2.1 From ed1abe16a35d5ea5cea1106f97c6dc08bfd5265c Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sun, 15 Apr 2018 19:30:52 +0200 Subject: urls: utilisation de la nouvelle syntaxe path de Django Mise à jour de la doc, nouvelles protections dans timetable_common() --- views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index de510a3..ebcf4ff 100644 --- a/views.py +++ b/views.py @@ -86,7 +86,10 @@ def timetable_common(request, obj, year=None, week=None, timetable=None): elif (int(year), int(week)) < (current_year, current_week): is_old_timetable = True - start, end = get_week(year, week) + try: + start, end = get_week(year, week) + except ValueError: + raise Http404 courses = Course.objects.get_courses(obj, begin__gte=start, begin__lt=end) if not courses.exists() and provided_week: -- cgit v1.2.1 From 88c1ca07d9846e43f3ce2c785a60fa85224dfe6d Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Fri, 20 Apr 2018 14:37:19 +0200 Subject: PEP8 --- views.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index ebcf4ff..1fc74b5 100644 --- a/views.py +++ b/views.py @@ -49,13 +49,16 @@ def mention_list(request, year_slug): def group_list(request, year_slug, timetable_slug): - timetable = get_object_or_404(Timetable, year__slug=year_slug, slug=timetable_slug) + timetable = get_object_or_404(Timetable, year__slug=year_slug, + slug=timetable_slug) start, _ = get_week(*get_current_week()) end = start + datetime.timedelta(weeks=4) - groups = Group.objects.get_relevant_groups(start, source=timetable.source, hidden=False) - groups_weeks = Course.objects.get_weeks(begin__gte=start, begin__lt=end, groups__in=groups) + groups = Group.objects.get_relevant_groups(start, source=timetable.source, + hidden=False) + groups_weeks = Course.objects.get_weeks(begin__gte=start, begin__lt=end, + groups__in=groups) for group in groups: for group_week in groups_weeks: @@ -97,20 +100,25 @@ def timetable_common(request, obj, year=None, week=None, timetable=None): # Récupération des semaines suivantes et précédentes pour les # afficher proprement dans l’emploi du temps - last_week = getattr(Course.objects.get_courses(obj, begin__lt=start).last(), "begin", None) - next_week = getattr(Course.objects.get_courses(obj, begin__gte=end).first(), "begin", None) + last_course = Course.objects.get_courses(obj, begin__lt=start).last() + last_week = getattr(last_course, "begin", None) + + next_course = Course.objects.get_courses(obj, begin__gte=end).first() + next_week = getattr(next_course, "begin", None) last_update = courses.aggregate(Max("last_update"))["last_update__max"] grouped_courses = group_courses(courses) - return render(request, "timetable.html", {"group": obj, "courses": grouped_courses, - "last_update": last_update, - "year": year, "week": int(week), - "last_week": last_week, - "next_week": next_week, - "is_old_timetable": is_old_timetable, - "group_mode": isinstance(obj, Group), - "timetable": timetable}) + return render(request, "timetable.html", + {"group": obj, "courses": grouped_courses, + "last_update": last_update, + "year": year, "week": int(week), + "last_week": last_week, + "next_week": next_week, + "is_old_timetable": is_old_timetable, + "group_mode": isinstance(obj, Group), + "timetable": timetable}) + def timetable(request, year_slug, timetable_slug, group_slug, year=None, week=None): -- cgit v1.2.1 From 7f0fa4871566050e283845ee0577603ded70df0f Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 21 Apr 2018 12:59:32 +0200 Subject: templates: abstraction et séparation des templates de liste --- views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index 1fc74b5..1308db1 100644 --- a/views.py +++ b/views.py @@ -37,14 +37,14 @@ if connection.vendor == "postgresql": def index(request): years = Year.objects.order_by("name") - return render(request, "index.html", {"elements": years}) + return render(request, "year_list.html", {"elements": years}) def mention_list(request, year_slug): year = get_object_or_404(Year, slug=year_slug) timetables = Timetable.objects.order_by("name").filter(year=year) - return render(request, "index.html", + return render(request, "mention_list.html", {"year": year, "elements": timetables}) -- cgit v1.2.1 From a6d14aa482e322fcd1946ea2541272477b4f8c6b Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 21 Apr 2018 15:20:01 +0200 Subject: Ajout d’une liste complète des groupes et d’une liste des semaines --- views.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'views.py') diff --git a/views.py b/views.py index 1308db1..aabda59 100644 --- a/views.py +++ b/views.py @@ -79,6 +79,43 @@ def group_list(request, year_slug, timetable_slug): {"timetable": timetable, "groups": groups}) +def groups_all(request, year_slug, timetable_slug): + # Récupération de l’emploi du temps et du groupe + timetable = get_object_or_404(Timetable, year__slug=year_slug, + slug=timetable_slug) + groups = Group.objects.filter(source=timetable.source).order_by("name") + + # Rendu de la page + return render(request, "groups_all_list.html", + {"timetable": timetable, "elements": groups}) + + +def group_weeks(request, year_slug, timetable_slug, group_slug): + # Récupération de l’emploi du temps et des groupes + timetable = get_object_or_404(Timetable, year__slug=year_slug, + slug=timetable_slug) + group = get_object_or_404(Group, slug=group_slug, source=timetable.source) + + # Groupes parents + groups = Group.objects.get_parents(group) + + # Récupération de toutes les semaines avec des cours, sans doublons + courses = Course.objects.filter(groups__in=groups) \ + .order_by("year", "week") \ + .annotate(year=ExtractYear("begin"), + week=ExtractWeek("begin")) \ + .values("year", "week") \ + .annotate(c=Count("*")) + + # Conversion des semaines de cours en dates + weeks = [get_week(course["year"], course["week"])[0] for course in courses] + + # Rendu + return render(request, "group_weeks_list.html", + {"timetable": timetable, "group": group, + "elements": weeks}) + + def timetable_common(request, obj, year=None, week=None, timetable=None): current_year, current_week = get_current_or_next_week() is_old_timetable, provided_week = False, True @@ -198,6 +235,23 @@ def rooms(request): return render(request, "group_list.html", {"groups": rooms_weeks}) +def room_weeks(request, room_slug): + room = get_object_or_404(Room, slug=room_slug) + + # Récupération des semaines de cours + courses = Course.objects.filter(rooms=room) \ + .order_by("year", "week") \ + .annotate(year=ExtractYear("begin"), + week=ExtractWeek("begin")) \ + .values("year", "week") \ + .annotate(c=Count("*")) + + weeks = [get_week(course["year"], course["week"])[0] for course in courses] + + return render(request, "room_weeks_list.html", + {"room": room, "elements": weeks}) + + def room_timetable(request, room_slug, year=None, week=None): room = get_object_or_404(Room, slug=room_slug) return timetable_common(request, room, year, week) -- cgit v1.2.1 From 60e3b389d065746d61906f91327867bfd5ed582c Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Wed, 25 Apr 2018 09:34:34 +0200 Subject: qsjps: abstraction et navigation de la template --- views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views.py') diff --git a/views.py b/views.py index aabda59..2411fe7 100644 --- a/views.py +++ b/views.py @@ -274,7 +274,7 @@ def qsjps(request): rooms = Room.objects.qsjps(begin, end) return render(request, "qsjps.html", - {"rooms": rooms, "form": form}) + {"elements": rooms, "form": form}) # Si le formulaire est invalide, on ré-affiche le formulaire # avec les erreurs -- cgit v1.2.1 From fb3a3bc214b071083325a75a9546331150eaa8a5 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Wed, 25 Apr 2018 09:35:18 +0200 Subject: templates: abstraction des listes de groupes/salles/semaines --- views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'views.py') diff --git a/views.py b/views.py index 2411fe7..e45ece3 100644 --- a/views.py +++ b/views.py @@ -76,7 +76,7 @@ def group_list(request, year_slug, timetable_slug): group.weeks.sort() return render(request, "group_list.html", - {"timetable": timetable, "groups": groups}) + {"timetable": timetable, "elements": groups}) def groups_all(request, year_slug, timetable_slug): @@ -199,7 +199,7 @@ def rooms(request): RawSQL("date_trunc('week', edt_course.begin)", []), distinct=True)) - return render(request, "group_list.html", {"groups": rooms}) + return render(request, "room_list.html", {"elements": rooms}) # Récupération des salles et de toutes les semaines où elles sont # concernées. @@ -232,7 +232,7 @@ def rooms(request): rooms_weeks[-1].weeks.append(date) # Rendu de la page. - return render(request, "group_list.html", {"groups": rooms_weeks}) + return render(request, "room_list.html", {"elements": rooms_weeks}) def room_weeks(request, room_slug): -- cgit v1.2.1