@ -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 :