{% endfor %}
diff --git a/odevzdavatko/templatetags/barvy_reseni.py b/odevzdavatko/templatetags/barvy_reseni.py
new file mode 100644
index 00000000..5a3791fd
--- /dev/null
+++ b/odevzdavatko/templatetags/barvy_reseni.py
@@ -0,0 +1,15 @@
+from django import template
+register = template.Library()
+
+from functools import cache
+import seminar.models as m
+
+@register.filter
+@cache
+def barva_reseni(r: m.Reseni):
+ """Vrátí nějakou barvu pro daný problém, ve tvaru '#RRGGBB'
+
+ Efektivně hešujeme do barev."""
+
+ #TODO: ne všechny barvy jsou dobře rozlišitelné a vidět…
+ return f'#{hash(str(r.id)) & 0xffffff:06x}'
diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py
index 35c99f68..41af1dcb 100644
--- a/odevzdavatko/views.py
+++ b/odevzdavatko/views.py
@@ -13,6 +13,7 @@ from django.db.models import Q
from dataclasses import dataclass
import datetime
+from decimal import Decimal
from itertools import groupby
import logging
@@ -37,14 +38,6 @@ logger = logging.getLogger(__name__)
# Taky se může hodit:
# - Tabulka všech řešitelů x všech problémů?
-@dataclass
-class SouhrnReseni:
- """Dataclass reprezentující data o odevzdaných řešeních pro zobrazení v tabulce."""
- pocet_reseni : int
- posledni_odevzdani : datetime.datetime
- body : float
-
-
class TabulkaOdevzdanychReseniView(ListView):
template_name = 'odevzdavatko/tabulka.html'
model = m.Hodnoceni
@@ -70,6 +63,7 @@ class TabulkaOdevzdanychReseniView(ListView):
reseni_od = fcd["reseni_od"]
reseni_do = fcd["reseni_do"]
jen_neobodovane = fcd["neobodovane"]
+ self.barvicky = fcd["barvicky"]
else:
initial = FiltrForm.gen_initial(self.aktualni_rocnik)
resitele = initial['resitele']
@@ -77,6 +71,7 @@ class TabulkaOdevzdanychReseniView(ListView):
reseni_od = initial['reseni_od'][0]
reseni_do = initial['reseni_do'][0]
jen_neobodovane = initial["neobodovane"]
+ self.barvicky = initial["barvicky"]
# Chceme jen letošní problémy
@@ -120,42 +115,45 @@ class TabulkaOdevzdanychReseniView(ListView):
return qs
def get_context_data(self, *args, **kwargs):
+ # TODO: refactor asi. Přepisoval jsem to jen syntakticky, nejspíš půlka kódu přestala dávat smysl…
# self.resitele, self.reseni a self.problemy jsou již nastavené
ctx = super().get_context_data(*args, **kwargs)
ctx['problemy'] = self.problemy
ctx['resitele'] = self.resitele
- tabulka = dict()
-
- def pridej_reseni(problem, resitel, body, cas):
+ tabulka: dict[m.Problem, dict[m.Resitel, list[tuple[m.Reseni, m.Hodnoceni]]]] = dict()
+ soucty: dict[m.Problem, dict[m.Resitel, Decimal]] = dict()
+
+ def pridej_reseni(resitel, hodnoceni):
+ problem = hodnoceni.problem
+ body = hodnoceni.body
+ cas = hodnoceni.reseni.cas_doruceni
+ reseni = hodnoceni.reseni
if problem not in tabulka:
tabulka[problem] = dict()
+ soucty[problem] = dict()
if resitel not in tabulka[problem]:
- tabulka[problem][resitel] = SouhrnReseni(pocet_reseni=1, posledni_odevzdani=cas, body=body)
+ tabulka[problem][resitel] = [(reseni, hodnoceni)]
+ soucty[problem][resitel] = hodnoceni.body or 0 # Neobodované neřešíme
else:
- tabulka[problem][resitel].posledni_odevzdani = max(tabulka[problem][resitel].posledni_odevzdani, cas)
- # Zvětšení počtu bodů o aktuální počet, pokud se tam někde nevyskytuje None – pak je součet taky None ("Pozor, nezadané body")
- tabulka[problem][resitel].body = tabulka[problem][resitel].body + body if body is not None and tabulka[problem][resitel].body is not None else None
- tabulka[problem][resitel].pocet_reseni += 1
- # Pro jednoduchost template si ještě poznamenáme ID problému a řešitele
- tabulka[problem][resitel].problem_id = problem.id
- tabulka[problem][resitel].resitel_id = resitel.id
+ tabulka[problem][resitel].append((reseni, hodnoceni))
+ soucty[problem][resitel] += hodnoceni.body or 0 # Neobodované neřešíme
for hodnoceni in self.get_queryset():
for resitel in hodnoceni.reseni.resitele.all():
- pridej_reseni(hodnoceni.problem, resitel, hodnoceni.body, hodnoceni.reseni.cas_doruceni)
+ pridej_reseni(resitel, hodnoceni)
- hodnoty = []
- resitele_do_tabulky = []
+ hodnoty: list[list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy + jejich součty, v každé buňce seznam řešení k danému řešiteli a problému.
+ resitele_do_tabulky: list[m.Resitel] = []
for resitel in self.resitele:
dostal_body = False
- resiteluv_radek = []
+ resiteluv_radek: list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]] = [] # podle pořadí v self.problemy
for problem in self.problemy:
if problem in tabulka and resitel in tabulka[problem]:
- resiteluv_radek.append(tabulka[problem][resitel])
+ resiteluv_radek.append((soucty[problem][resitel], tabulka[problem][resitel]))
dostal_body = True
else:
- resiteluv_radek.append(None)
+ resiteluv_radek.append((Decimal(0),[]))
if self.chteni_resitele != FiltrForm.RESITELE_RELEVANTNI or dostal_body:
hodnoty.append(resiteluv_radek)
resitele_do_tabulky.append(resitel)
@@ -165,6 +163,7 @@ class TabulkaOdevzdanychReseniView(ListView):
ctx['form'] = ctx['filtr']
# Pro maximum v přesměrovátku ročníků
ctx['aktualni_rocnik'] = m.Nastaveni.get_solo().aktualni_rocnik
+ ctx['barvicky'] = self.barvicky
if 'rocnik' in self.kwargs:
ctx['rocnik'] = self.kwargs['rocnik']
else:
@@ -174,6 +173,11 @@ class TabulkaOdevzdanychReseniView(ListView):
# Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji?
class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View):
+ """Rozskok mezi více řešeními téhož problému od téhož řešitele.
+
+ Asi už bude zastaralý v okamžiku, kdy se tenhle komentář nasadí na produkci :-)
+
+ V případě, že takové řešení existuje jen jedno, tak na něj přesměruje."""
model = m.Reseni
template_name = 'odevzdavatko/seznam.html'