diff --git a/seminar/templates/seminar/archiv/rocnik.html b/seminar/templates/seminar/archiv/rocnik.html index 64c4029d..c047a5b1 100644 --- a/seminar/templates/seminar/archiv/rocnik.html +++ b/seminar/templates/seminar/archiv/rocnik.html @@ -42,7 +42,7 @@ {% if user.is_staff and vysledkovka_s_neverejnymi %}

Výsledková listina včetně neveřejných bodů

- {% with vysledkovka_s_neverejnymi as vysledkovka %} + {% with radky_vyledkovky_s_neverejnymi as radky_vysledkovky %} {% include "seminar/vysledkovka_rocnik.html" %} {% endwith %}
diff --git a/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex b/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex index 75d8eb79..4218de57 100644 --- a/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex +++ b/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex @@ -7,7 +7,7 @@ \endhead \hline \endfoot -{% for rv in vysledkovka.radky %}{{ rv.poradi }} & {% if rv.titul %}\titul{{ lb }}{{ rv.titul }}}~{% endif %}{{ rv.resitel.jmeno|slice:":1" }}.~{{ rv.resitel.prijmeni }} & {% if rv.resitel.rocnik %}{{ rv.resitel.rocnik }}.{% endif %} & {{ rv.body_odjakziva }} {% for b in rv.body_cisla %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\ +{% for rv in radky_vysledkovky %}{{ rv.poradi }} & {% if rv.titul %}\titul{{ lb }}{{ rv.titul }}}~{% endif %}{{ rv.resitel.osoba.jmeno|slice:":1" }}.~{{ rv.resitel.osoba.prijmeni }} & {% if rv.resitel.rocnik %}{{ rv.resitel.rocnik }}.{% endif %} & {{ rv.body_odjakziva }} {% for b in rv.body_cisla_sezn %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\ {% endfor %}\end{longtable} {% endwith %} {% endwith %} diff --git a/seminar/templates/seminar/vysledkovka_rocnik.html b/seminar/templates/seminar/vysledkovka_rocnik.html index f1dc1d79..424f805b 100644 --- a/seminar/templates/seminar/vysledkovka_rocnik.html +++ b/seminar/templates/seminar/vysledkovka_rocnik.html @@ -4,23 +4,23 @@ Jméno R. Odjakživa - {% for c in vysledkovka.cisla %} + {% for c in cisla %} - {{c.rocnik.rocnik}}.{{ c.cislo }} + {{c.rocnik.rocnik}}.{{ c.poradi }} {% endfor %} Celkem -{% for rv in vysledkovka.radky %} +{% for rv in radky_vysledkovky %} {% autoescape off %}{{ rv.poradi }}{% endautoescape %} {% if rv.titul %} {{ rv.titul }}MM {% endif %} - {{ rv.resitel.plne_jmeno }} + {{ rv.resitel.osoba.plne_jmeno }} {{ rv.resitel.rocnik }} - {{ rv.body_odjakziva }} - {% for b in rv.body_cisla %} + {{ rv.body_celkem_odjakziva }} + {% for b in rv.body_cisla_sezn %} {{ b }} {% endfor %} {{ rv.body_rocnik }} diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 01546843..771c204c 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -388,13 +388,17 @@ class ArchivView(generic.ListView): ### Výsledky -# ze setřízeného(!) seznamu všech bodů vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.) -def sloupec_s_poradim(seznam_s_body): +# ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník +# vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.), +# podle toho, jak jdou za sebou ve výsledkovce +def sloupec_s_poradim(setrizene_body): + + # ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím aktualni_poradi = 1 sloupec_s_poradim = [] # seskupíme seznam všech bodů podle hodnot - for index in range(0, len(seznam_s_body)): + for index in range(0, len(setrizene_body)): # pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme # vypsat už jen prázdné místo, než dojdeme na správný řádek if (index + 1) < aktualni_poradi: @@ -402,10 +406,10 @@ def sloupec_s_poradim(seznam_s_body): continue velikost_skupiny = 0 # zjistíme počet po sobě jdoucích stejných hodnot - while seznam_s_body[index] == seznam_s_body[index + velikost_skupiny]: + while setrizene_body[index] == setrizene_body[index + velikost_skupiny]: velikost_skupiny = velikost_skupiny + 1 # na konci musíme ošetřit přetečení seznamu - if (index + velikost_skupiny) > len(seznam_s_body) - 1: + if (index + velikost_skupiny) > len(setrizene_body) - 1: break # pokud je velikost skupiny 1, vypíšu pořadí if velikost_skupiny == 1: @@ -418,28 +422,12 @@ def sloupec_s_poradim(seznam_s_body): aktualni_poradi = aktualni_poradi + velikost_skupiny return sloupec_s_poradim -## spočítá součet bodů získaných daným řešitelem za zadaný problém a všechny jeho podproblémy -#def __soucet_resitele_problemu(problem, resitel, cislo, soucet): -# # sečteme body za daný problém přes všechna řešení daného problému -# # od daného řešitele -# reseni_resitele = s.Reseni_Resitele.objects.filter(resitele=resitel) -# hodnoceni_resitele = problem.hodnoceni.filter(reseni__in=reseni_resitele, -# cislo_body=cislo) -# # XXX chyba na řádku výše - řešení může mít více řešitelů, asi chceme contains -# # nebo in -# for r in hodnoceni_resitele: -# soucet += r.body -# -# # a přičteme k tomu hodnocení všech podproblémů -# for p in problem.podproblem.all(): -# # i přes jméno by to měla být množina jeho podproblémů -# soucet += __soucet_resitele_problemu(p, resitel, soucet) -# return soucet - -## spočítá součet všech bodů ze všech podproblémů daného problému daného řešitele -#def body_resitele_problemu_v_cisle(problem, resitel, cislo): -# # probably FIXED: nezohledňuje číslo, do kterého se body počítají -# return __soucet_resitele_problemu(problem, resitel, cislo, 0) +# vrátí všechna čísla daného ročníku +def cisla_rocniku(rocnik, jen_verejne=True): + if jen_verejne: + return rocnik.verejna_cisla() + else: + return rocnik.cisla.all() # pro daný problém vrátí jeho nejvyšší nadproblém def hlavni_problem(problem): @@ -447,6 +435,17 @@ def hlavni_problem(problem): problem = problem.nadproblem return problem +def hlavni_problemy_rocniku(rocnik, jen_verejne=True): + hlavni_problemy = [] + for cislo in cisla_rocniku(rocnik, jen_verejne): + for problem in hlavni_problemy_cisla(cislo): + hlavni_problemy.append(problem) + hlavni_problemy_set = set(hlavni_problemy) + hlavni_problemy = list(hlavni_problemy_set) + hlavni_problemy.sort(key=lambda k:k.kod_v_rocniku()) # setřídit podle pořadí + + return hlavni_problemy + # vrátí list všech problémů s body v daném čísle, které již nemají nadproblém def hlavni_problemy_cisla(cislo): hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all() @@ -476,27 +475,32 @@ def body_resitelu_odjakziva(rocnik, resitele): for r in resitele: body_odjakziva[str(r.id)] = 0 -# POZOR! Aktuálně počítá jen za posledních 10 let od zadaného ročníku -# # Body za posledních 10 let je dobrá aproximace pro naše potřeby (výsledkovka -# # s aktivními řešiteli) -# -# body_pred_roky = [] -# for i in range(0, 10): -# body_pred_roky.append(body_resitelu_za_rocnik(rocnik-i, resitele)) -# -# for r in resitele: -# for i in range(0,10): -# body_odjakziva[str(r.id)] += body_pred_roky[i][str(r.id)] - - -# Nasledující řešení je sice správné, ale moc pomalé: - for res in Reseni.objects.prefetch_related('resitele', 'hodnoceni_set').all(): - for r in res.resitele.all(): - # daný řešitel nemusí být v naší podmnožině - if r not in resitele: continue - - for hodn in res.hodnoceni_set.all(): - pricti_body(body_odjakziva, r, hodn.body) +######################################################################### +# POZOR! Aktuálně počítá jen za posledních 10 let od zadaného ročníku # +######################################################################### + # Body za posledních 10 let je dobrá aproximace pro naše potřeby (výsledkovka + # s aktivními řešiteli) + + body_pred_roky = [] + rok = rocnik.prvni_rok + rocniky = Rocnik.objects.filter(prvni_rok__gt=rok-11) + for roc in rocniky: + body_pred_roky.append(body_resitelu_za_rocnik(roc, resitele)) + + for r in resitele: + for i in range(0,10): + body_odjakziva[str(r.id)] += body_pred_roky[i][str(r.id)] + + +# Nasledující řešení je sice správné, ale moc pomalé: +# (důsledek toho, že dotazy na joinování databázových tabulek jsou kvadratické) +# for res in Reseni.objects.prefetch_related('resitele', 'hodnoceni_set').all(): +# for r in res.resitele.all(): +# # daný řešitel nemusí být v naší podmnožině +# if r not in resitele: continue +# +# for hodn in res.hodnoceni_set.all(): +# pricti_body(body_odjakziva, r, hodn.body) return body_odjakziva # vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník @@ -514,13 +518,77 @@ def body_resitelu_za_rocnik(rocnik, aktivni_resitele): pricti_body(body_za_rocnik, resitel, hodn.body) return body_za_rocnik -# TODO: předělat na nový model -#def vysledkovka_rocniku(rocnik, jen_verejne=True): -# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve -# formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" -# """ -# -# #vyberu vsechny vysledky z rocniku +class RadekVysledkovkyRocniku(object): + """Obsahuje věci, které se hodí vědět při konstruování výsledkovky. + Umožňuje snazší práci v templatu (lepší, než seznam).""" + + def __init__(self, poradi, resitel, body_cisla_sezn, body_rocnik, body_odjakziva): + self.poradi = poradi + self.resitel = resitel + self.body_rocnik = body_rocnik + self.body_celkem_odjakziva = body_odjakziva + self.body_cisla_sezn = body_cisla_sezn + self.titul = resitel.get_titul(body_odjakziva) + +def vysledkovka_rocniku(rocnik, jen_verejne=True): + """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve + formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" + """ + + ## TODO možná chytřeji vybírat aktivní řešitele + # aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají + # u alespoň jedné hodnoty něco jiného než NULL + aktivni_resitele = list(Resitel.objects.filter( + rok_maturity__gte=rocnik.druhy_rok())) + # TODO: zkusit hodnoceni__rocnik... + #.filter(hodnoceni_set__rocnik__eq=cislo_rocnik) + cisla = cisla_rocniku(rocnik, jen_verejne) + body_cisla_slov = {} + print("Jen veřejná: {}, čísla: {}".format(jen_verejne, cisla)) + for cislo in cisla: + # získáme body za číslo + _, cislobody = secti_body_za_cislo(cislo, aktivni_resitele) + body_cisla_slov[str(cislo.id)] = cislobody + + # získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně + resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele) + + # setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší + setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] + setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id] + setrizene_body = [dvojice[1] for dvojice in resitel_rocnikbody_sezn] + poradi = sloupec_s_poradim(setrizene_body) + + # získáme body odjakživa + resitel_odjakzivabody_slov = body_resitelu_odjakziva(rocnik, aktivni_resitele) + + # vytvoříme jednotlivé sloupce výsledkovky + radky_vysledkovky = [] + i = 0 + for ar_id in setrizeni_resitele_id: + # seznam počtu bodů daného řešitele pro jednotlivá čísla + body_cisla_sezn = [] + for cislo in cisla: + body_cisla_sezn.append(body_cisla_slov[str(cislo.id)][str(ar_id)]) + + # vytáhneme informace pro daného řešitele + radek = RadekVysledkovkyRocniku( + poradi[i], # pořadí + Resitel.objects.get(id=ar_id), # řešitel (z id) + body_cisla_sezn, # seznam bodů za čísla + setrizene_body[i], # body za ročník (spočítané výše s pořadím) + resitel_odjakzivabody_slov[ar_id]) # body odjakživa + print("{}: číslobody - {}, ročníkbody - {}," + "odjakživabody - {}".format(radek.resitel, radek.body_cisla_sezn, + radek.body_rocnik, radek.body_celkem_odjakziva)) + radky_vysledkovky.append(radek) + print("Přikládám {}-tý řádek.".format(i)) + i += 1 + + return radky_vysledkovky + + + #vyberu vsechny vysledky z rocniku # cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__rocnik=rocnik).order_by('cislo') # if jen_verejne: # cisla_v_rocniku = cisla_v_rocniku.filter(cislo__verejna_vysledkovka=True) @@ -594,10 +662,15 @@ class RocnikView(generic.DetailView): def get_context_data(self, **kwargs): context = super(RocnikView, self).get_context_data(**kwargs) - #context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"]) - #context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False) - #context['temata_v_rocniku'] = verejna_temata(context["rocnik"]) - # FIXME: opravit vylistování témat v ročníku + # vysledkovka = True zajistí vykreslení, + # zkontrolovat, kdy se má a nemá vykreslovat + context['vysledkovka'] = True + context['cisla_s_neverejnymi'] = cisla_rocniku(context["rocnik"], jen_verejne=False) + context['cisla'] = cisla_rocniku(context["rocnik"]) + context['radky_vysledkovky'] = vysledkovka_rocniku(context["rocnik"]) + context['radky_vysledkovky_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False) + context['hlavni_problemy_v_rocniku'] = hlavni_problemy_rocniku(context["rocnik"]) + context['hlavni_problemy_v_rocniku_s_neverejnymi'] = hlavni_problemy_rocniku(context["rocnik"], jen_verejne=False) return context @@ -621,7 +694,7 @@ class ProblemView(generic.DetailView): return context -class RadekVysledkovky(object): +class RadekVysledkovkyCisla(object): """Obsahuje věci, které se hodí vědět při konstruování výsledkovky. Umožňuje snazší práci v templatu (lepší, než seznam).""" @@ -647,19 +720,22 @@ def pricti_body(slovnik, resitel, body): slovnik[str(resitel.id)] += body -def secti_body_za_rocnik(cislo, aktivni_resitele): +def secti_body_za_rocnik(rocnik, aktivni_resitele): # spočítáme všem řešitelům jejich body za ročník - resitel_rocnikbody_slov = body_resitelu_za_rocnik(cislo.rocnik, aktivni_resitele) + resitel_rocnikbody_slov = body_resitelu_za_rocnik(rocnik, aktivni_resitele) # zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(), key = lambda x: x[1], reverse = True) return resitel_rocnikbody_sezn # spočítá u řešitelů body za číslo a za jednotlivé hlavní problémy (témata) -def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy): +def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None): # TODO setřídit hlavní problémy čísla podle id, ať jsou ve stejném pořadí pokaždé # pro každý hlavní problém zavedeme slovník s body za daný hlavní problém # pro jednotlivé řešitele (slovník slovníků hlavních problémů) + if hlavni_problemy is None: + hlavni_problemy = hlavni_problemy_cisla(cislo) + hlavni_problemy_slovnik = {} for hp in hlavni_problemy: hlavni_problemy_slovnik[str(hp.id)] = {} @@ -697,12 +773,11 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy): return hlavni_problemy_slovnik, cislobody -def spocti_vysledkovku_cisla(cislo, context=None): +def vysledkovka_cisla(cislo, context=None): if context is None: context = {} hlavni_problemy = hlavni_problemy_cisla(cislo) - ## TODO dostat pro tyto problémy součet v daném čísle pro daného řešitele ## TODO možná chytřeji vybírat aktivní řešitele # aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají # u alespoň jedné hodnoty něco jiného než NULL @@ -715,10 +790,10 @@ def spocti_vysledkovku_cisla(cislo, context=None): hlavni_problemy_slovnik, cislobody = secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy) # získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně - resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo, aktivni_resitele) + resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo.rocnik, aktivni_resitele) # získáme body odjakživa - resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik.druhy_rok(), + resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik, aktivni_resitele) # řešitelé setřídění podle bodů za číslo sestupně @@ -738,7 +813,7 @@ def spocti_vysledkovku_cisla(cislo, context=None): for hp in hlavni_problemy: problemy.append(hlavni_problemy_slovnik[str(hp.id)][ar_id]) # vytáhneme informace pro daného řešitele - radek = RadekVysledkovky( + radek = RadekVysledkovkyCisla( poradi[i], # pořadí Resitel.objects.get(id=ar_id), # řešitel (z id) problemy, # seznam bodů za hlavní problémy čísla @@ -785,7 +860,7 @@ class CisloView(generic.DetailView): cislo = context['cislo'] # vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky - return spocti_vysledkovku_cisla(cislo, context) + return vysledkovka_cisla(cislo, context) # problemy = sorted(set(r.problem for r in reseni), key=lambda x:(poradi_typu[x.typ], x.kod_v_rocniku())) # #setridi problemy podle typu a poradi zadani @@ -844,13 +919,13 @@ class ArchivTemataView(generic.ListView): # content_type = 'text/plain; charset=UTF8' # #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani # -#class RocnikVysledkovkaView(RocnikView): -# model = Rocnik -# template_name = 'seminar/archiv/rocnik_vysledkovka.tex' -# #content_type = 'application/x-tex; charset=UTF8' -# #umozni rovnou stahnout TeXovsky dokument -# content_type = 'text/plain; charset=UTF8' -# #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani +class RocnikVysledkovkaView(RocnikView): + model = Rocnik + template_name = 'seminar/archiv/rocnik_vysledkovka.tex' + #content_type = 'application/x-tex; charset=UTF8' + #umozni rovnou stahnout TeXovsky dokument + content_type = 'text/plain; charset=UTF8' + #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani ### Generovani obalek class CisloObalkyStruct: