@ -1,298 +1,277 @@
import abc
from functools import cached_property
import seminar . models as m
import seminar . models as m
from django . db . models import Q , Sum , Count
from django . db . models import Q , Sum
from seminar . utils import aktivniResitele , resi_v_rocniku , cisla_rocniku , hlavni_problem , hlavni_problemy_f , problemy_cisla , podproblemy_v_cislu
from seminar . utils import resi_v_rocniku , cisla_rocniku , hlavni_problem , \
import time
hlavni_problemy_f , problemy_cisla , podproblemy_v_cislu
ROCNIK_ZRUSENI_TEMAT = 25
ROCNIK_ZRUSENI_TEMAT = 25
def sloupec_s_poradim ( setrizene_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 .
Parametr :
setrizene_body ( seznam integerů ) : sestupně setřízená čísla
Výstup :
class FixedIterator :
sloupec_s_poradim ( seznam stringů )
def next ( self ) :
"""
return self . niter . __next__ ( )
def __init__ ( self , niter ) :
self . niter = niter
def body_resitelu (
za = None ,
do : m . Deadline = None ,
od : m . Deadline = None ,
jen_verejne : bool = True ,
resitele = None ,
null = 0
) - > dict [ int , int ] :
filtr = Q ( )
if jen_verejne :
filtr & = Q ( reseni__hodnoceni__deadline_body__verejna_vysledkovka = True )
# Zjistíme, typ objektu v parametru "za"
if isinstance ( za , m . Rocnik ) :
filtr & = Q ( reseni__hodnoceni__deadline_body__cislo__rocnik = za )
elif isinstance ( za , m . Cislo ) :
filtr & = Q ( reseni__hodnoceni__deadline_body__cislo = za )
if do :
filtr & = Q ( reseni__hodnoceni__deadline_body__lte = do )
if od :
filtr & = Q ( reseni__hodnoceni__deadline_body__gte = od )
resiteleQuery = m . Resitel . objects . all ( )
if resitele is not None :
resitele_id = [ r . id for r in resitele ]
resiteleQuery = resiteleQuery . filter ( id__in = resitele_id )
# Přidáme ke každému řešiteli údaj ".body" se součtem jejich bodů
resitele_s_body = resiteleQuery . annotate (
body = Sum ( ' reseni__hodnoceni__body ' , filter = filtr ) )
# Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník
# indexovaný řešitelským id obsahující body.
# Pokud jsou body None, nahradíme za 0.
slovnik = {
int ( res . id ) : ( res . body if res . body else null ) for res in resitele_s_body
}
return slovnik
class Vysledkovka ( abc . ABC ) :
jen_verejne : bool
rocnik : m . Rocnik
do_deadlinu : m . Deadline
@property
@abc . abstractmethod
def aktivni_resitele ( self ) - > list [ m . Resitel ] :
. . .
@cached_property
def resitele_s_body_za_rocnik_setrizeny_seznam ( self ) - > list [ tuple [ int , int ] ] :
# spočítáme všem řešitelům jejich body za ročník
resitel_body_za_rocnik_slovnik = body_resitelu (
resitele = self . aktivni_resitele ,
za = self . rocnik ,
jen_verejne = self . jen_verejne ,
do = self . do_deadlinu
)
# zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně
resitele_s_body_za_rocnik_setrizeny_seznam = sorted (
resitel_body_za_rocnik_slovnik . items ( ) ,
key = lambda x : x [ 1 ] , reverse = True
)
return resitele_s_body_za_rocnik_setrizeny_seznam
@cached_property
def body_za_rocnik_seznamy ( self ) - > tuple [ list [ int ] , list [ int ] ] :
if len ( self . resitele_s_body_za_rocnik_setrizeny_seznam ) == 0 :
return [ ] , [ ]
return tuple ( zip ( * self . resitele_s_body_za_rocnik_setrizeny_seznam ) )
@cached_property
def setrizeni_resitele_id ( self ) - > list [ int ] :
return self . body_za_rocnik_seznamy [ 0 ]
@cached_property
def setrizene_body ( self ) - > list [ int ] :
return self . body_za_rocnik_seznamy [ 1 ]
@cached_property
def resitel_body_odjakziva_slovnik ( self ) - > dict [ int , int ] :
return body_resitelu ( jen_verejne = self . jen_verejne , do = self . do_deadlinu )
@cached_property
def poradi ( self ) :
# ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím
# ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím
aktualni_poradi = 1
aktualni_poradi = 1
sloupec_s_poradim = [ ]
sloupec_s_poradim = [ ]
# seskupíme seznam všech bodů podle hodnot
# seskupíme seznam všech bodů podle hodnot
for index in range ( 0 , len ( setrizene_body ) ) :
for index in range ( 0 , len ( self . setrizene_body ) ) :
# pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme
# pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah
# vypsat už jen prázdné místo, než dojdeme na správný řádek
# a chceme vypsat už jen prázdné místo, než dojdeme na správný řádek
if ( index + 1 ) < aktualni_poradi :
if ( index + 1 ) < aktualni_poradi :
sloupec_s_poradim . append ( " " )
sloupec_s_poradim . append ( " " )
continue
continue
velikost_skupiny = 0
velikost_skupiny = 0
# zjistíme počet po sobě jdoucích stejných hodnot
# zjistíme počet po sobě jdoucích stejných hodnot
while setrizene_body [ index ] == setrizene_body [ index + velikost_skupiny ] :
while self . setrizene_body [ index ] == self . setrizene_body [
velikost_skupiny = velikost_skupiny + 1
index + velikost_skupiny ] :
velikost_skupiny + = 1
# na konci musíme ošetřit přetečení seznamu
# na konci musíme ošetřit přetečení seznamu
if ( index + velikost_skupiny ) > len ( setrizene_body ) - 1 :
if ( index + velikost_skupiny ) > len ( self . setrizene_body ) - 1 :
break
break
# pokud je velikost skupiny 1, vypíšu pořadí
# pokud je velikost skupiny 1, vypíšu pořadí
if velikost_skupiny == 1 :
if velikost_skupiny == 1 :
sloupec_s_poradim . append ( " {} . " . format ( aktualni_poradi ) )
sloupec_s_poradim . append ( f " { aktualni_poradi } . " )
# pokud je skupina větší, vypíšu rozsah
# pokud je skupina větší, vypíšu rozsah
else :
else :
sloupec_s_poradim . append ( " {} .– {} . " . format ( aktualni_poradi ,
sloupec_s_poradim . append (
aktualni_poradi + velikost_skupiny - 1 ) )
f " { aktualni_poradi } .– { aktualni_poradi + velikost_skupiny - 1 } . "
)
# zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno
# zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno
aktualni_poradi = aktualni_poradi + velikost_skupiny
aktualni_poradi + = velikost_skupiny
return sloupec_s_poradim
return sloupec_s_poradim
class VysledkovkaRocniku ( Vysledkovka ) :
def __init__ ( self , rocnik : m . Rocnik , jen_verejne : bool = True ) :
self . rocnik = rocnik
self . jen_verejne = jen_verejne
self . do_deadlinu = m . Deadline . objects . filter ( cislo__rocnik = rocnik ) . last ( )
def body_resitelu ( resitele , za , odjakziva = True , jen_verejne = False ) :
@cached_property
""" Funkce počítající počty bodů pro zadané řešitele,
def aktivni_resitele ( self ) - > list [ m . Resitel ] :
buď odjakživa do daného ročníku / čísla anebo za daný ročník / číslo .
return list ( resi_v_rocniku ( self . rocnik ) )
Parametry :
resitele ( seznam obsahující položky typu Resitel ) : aktivní řešitelé
za ( Rocnik / Cislo ) : za co se mají počítat body
( generování starších výsledkovek )
odjakziva ( bool ) : zda se mají počítat body odjakživa , nebo jen za číslo / ročník
zadané v " za "
Výstup :
slovník ( Resitel . id ) : body
"""
resitele_id = [ r . id for r in resitele ]
# Zjistíme, typ objektu v parametru "za"
if isinstance ( za , m . Rocnik ) :
cislo = None
rocnik = za
rok = rocnik . prvni_rok
elif isinstance ( za , m . Cislo ) :
cislo = za
rocnik = None
rok = cislo . rocnik . prvni_rok
else :
assert True , " body_resitelu: za není ani číslo ani ročník. "
# Kvůli rychlosti používáme sčítáme body už v databázi, viz
# https://docs.djangoproject.com/en/3.0/topics/db/aggregation/,
# sekce Filtering on annotations (protože potřebujeme filtrovat výsledky
# jen do nějakého data, abychom uměli správně nagenerovat výsledkovky i
# za historická čísla.
# Níže se vytváří dotaz na součet bodů za správně vyfiltrovaná hodnocení,
# který se použije ve výsledném dotazu.
if cislo and odjakziva : # Body se sčítají odjakživa do zadaného čísla.
# Vyfiltrujeme všechna hodnocení, která jsou buď ze starších ročníků,
# anebo ze stejného ročníku, jak je zadané číslo, tam ale sčítáme jen
# pro čísla s pořadím nejvýše stejným, jako má zadané číslo.
body_k_zapocteni = Sum ( ' reseni__hodnoceni__body ' ,
filter = ( Q ( reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lt = rok ) |
Q ( reseni__hodnoceni__cislo_body__rocnik__prvni_rok = rok ,
reseni__hodnoceni__cislo_body__poradi__lte = cislo . poradi ) ) )
elif cislo and not odjakziva : # Body se sčítají za dané číslo.
body_k_zapocteni = Sum ( ' reseni__hodnoceni__body ' ,
filter = ( Q ( reseni__hodnoceni__cislo_body__rocnik__prvni_rok = rok ,
reseni__hodnoceni__cislo_body__poradi__lte = cislo . poradi ) ) )
elif rocnik and odjakziva : # Spočítáme body za starší ročníky až do zadaného včetně.
if jen_verejne :
body_k_zapocteni = Sum ( ' reseni__hodnoceni__body ' ,
filter = Q ( reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte = rok ,
reseni__hodnoceni__cislo_body__verejna_vysledkovka = True ) )
else :
body_k_zapocteni = Sum ( ' reseni__hodnoceni__body ' ,
filter = Q ( reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte = rok ) )
elif rocnik and not odjakziva : # Spočítáme body za daný ročník.
if jen_verejne :
body_k_zapocteni = Sum ( ' reseni__hodnoceni__body ' ,
filter = Q ( reseni__hodnoceni__cislo_body__rocnik = rocnik ,
reseni__hodnoceni__cislo_body__verejna_vysledkovka = True ) )
else :
body_k_zapocteni = Sum ( ' reseni__hodnoceni__body ' ,
filter = Q ( reseni__hodnoceni__cislo_body__rocnik = rocnik ) )
else :
assert True , " body_resitelu: Neplatná kombinace za a odjakživa. "
# Následující řádek přidá ke každému řešiteli údaj ".body" se součtem jejich bodů
@cached_property
resitele_s_body = m . Resitel . objects . filter ( id__in = resitele_id ) . annotate (
def cisla_rocniku ( self ) - > list [ m . Cislo ] :
body = body_k_zapocteni )
return cisla_rocniku ( self . rocnik , self . jen_verejne )
# Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník
# indexovaný řešitelským id obsahující body.
@cached_property
# Pokud jsou body None, nahradíme za 0.
def body_za_cisla_slovnik ( self ) - > dict [ int , dict [ int , int ] ] :
slovnik = { int ( res . id ) : ( res . body if res . body else 0 ) for res in resitele_s_body }
body_cisla_slovnik = dict ( )
return slovnik
for cislo in self . cisla_rocniku :
# získáme body za číslo
body_za_cislo = body_resitelu (
za = cislo ,
resitele = self . aktivni_resitele ,
jen_verejne = self . jen_verejne ,
null = " "
)
body_cisla_slovnik [ cislo . id ] = body_za_cislo
return body_cisla_slovnik
class RadekVysledkovkyRocniku ( object ) :
class RadekVysledkovkyRocniku :
""" Obsahuje věci, které se hodí vědět při konstruování výsledkovky.
""" 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 ) . """
Umožňuje snazší práci v templatu ( lepší , než seznam ) . """
def __init__ ( self , poradi , resitel , body_cisla_sezn , body_rocnik , body_odjakziva , rok ) :
def __init__ ( self , poradi , resitel , body_cisla_seznam , body_rocnik , body_odjakziva , rok ) :
self . poradi = poradi
self . poradi = poradi
self . resitel = resitel
self . resitel = resitel
self . rocnik_resitele = resitel . rocnik ( rok )
self . rocnik_resitele = resitel . rocnik ( rok )
self . body_rocnik = body_rocnik
self . body_rocnik = body_rocnik
self . body_celkem_odjakziva = body_odjakziva
self . body_celkem_odjakziva = body_odjakziva
self . body_cisla_sezn = body_cisla_sezn
self . body_cisla_seznam = body_cisla_seznam
self . titul = resitel . get_titul ( body_odjakziva )
self . titul = resitel . get_titul ( body_odjakziva )
def setrid_resitele_a_body ( slov_resitel_body ) :
@cached_property
setrizeni_resitele_id = [ dvojice [ 0 ] for dvojice in slov_resitel_body ]
def radky_vysledkovky ( self ) - > list [ RadekVysledkovkyRocniku ] :
setrizene_body = [ dvojice [ 1 ] for dvojice in slov_resitel_body ]
return setrizeni_resitele_id , setrizene_body
def data_vysledkovky_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 "
"""
start = time . time ( )
## 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 ( resi_v_rocniku ( rocnik ) )
cisla = cisla_rocniku ( rocnik , jen_verejne )
body_cisla_slov = { }
for cislo in cisla :
# získáme body za číslo
_ , cislobody = secti_body_za_cislo ( cislo , aktivni_resitele )
body_cisla_slov [ 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 , jen_verejne = jen_verejne )
# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší
setrizeni_resitele_id , setrizene_body = setrid_resitele_a_body ( resitel_rocnikbody_sezn )
poradi = sloupec_s_poradim ( setrizene_body )
# získáme body odjakživa
resitel_odjakzivabody_slov = body_resitelu ( aktivni_resitele , rocnik , jen_verejne = jen_verejne )
# vytvoříme jednotlivé sloupce výsledkovky
radky_vysledkovky = [ ]
radky_vysledkovky = [ ]
i = 0
i = 0
setrizeni_resitele_dict = { } # Tento slovnik se vyrab
setrizeni_resitele_dict = dict ( )
for r in m . Resitel . objects . filter ( id__in = setrizeni_resitele_id ) . select_related ( ' osoba ' ) :
for r in m . Resitel . objects . filter (
id__in = self . setrizeni_resitele_id
) . select_related ( ' osoba ' ) :
setrizeni_resitele_dict [ r . id ] = r
setrizeni_resitele_dict [ r . id ] = r
for ar_id in setrizeni_resitele_id :
for ar_id in self . setrizeni_resitele_id :
if self . setrizene_body [ i ] > 0 :
# seznam počtu bodů daného řešitele pro jednotlivá čísla
# seznam počtu bodů daného řešitele pro jednotlivá čísla
body_cisla_sezn = [ ]
body_cisla_seznam = [ ]
for cislo in cisla :
for cislo in self . cisla_rocniku :
body_cisla_sezn . append ( body_cisla_slov [ cislo . id ] [ ar_id ] )
body_cisla_seznam . append ( self . body_za_cisla_slovnik [ cislo . id ] [ ar_id ] )
# Pokud řešitel dostal nějaké body
if self . resitele_s_body_za_rocnik_setrizeny_seznam [ i ] != 0 :
# vytáhneme informace pro daného řešitele
# vytáhneme informace pro daného řešitele
radek = RadekVysledkovkyRocniku (
radek = self . RadekVysledkovkyRocniku (
poradi [ i ] , # pořadí
poradi = self . poradi [ i ] ,
setrizeni_resitele_dict [ ar_id ] , # řešitel (z id)
resitel = setrizeni_resitele_dict [ ar_id ] ,
body_cisla_sezn , # seznam bodů za čísla
body_cisla_seznam = body_cisla_seznam ,
setrizene_body [ i ] , # body za ročník (spočítané výše s pořadím)
body_rocnik = self . setrizene_body [ i ] ,
resitel_odjakzivabody_slov [ ar_id ] , # body odjakživa
body_odjakziva = self . resitel_body_odjakziva_slovnik [ ar_id ] ,
rocnik ) # ročník semináře pro získání ročníku řešitele
rok = self . rocnik ) # ročník semináře pro získání ročníku řešitele
radky_vysledkovky . append ( radek )
radky_vysledkovky . append ( radek )
i + = 1
end = time . time ( )
print ( " Vysledkovka rocniku " , end - start )
radky_vysledkovky = [ radek for radek in radky_vysledkovky if radek . body_rocnik > 0 ]
return radky_vysledkovky , cisla
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 ) . """
def __init__ ( self , poradi , resitel , body_problemy_sezn ,
body_cislo , body_rocnik , body_odjakziva , rok , body_podproblemy , body_podproblemy_iter ) :
self . resitel = resitel
self . rocnik_resitele = resitel . rocnik ( rok )
self . body_cislo = body_cislo
self . body_rocnik = body_rocnik
self . body_celkem_odjakziva = body_odjakziva
self . poradi = poradi
self . body_problemy_sezn = body_problemy_sezn
self . titul = resitel . get_titul ( body_odjakziva )
self . body_podproblemy = body_podproblemy
self . body_podproblemy_iter = body_podproblemy_iter # TODELETE
def pricti_body ( slovnik , resitel , body ) :
""" Přiřazuje danému řešiteli body do slovníku. """
# testujeme na None (""), pokud je to první řešení
# daného řešitele, předěláme na 0
# (v dalším kroku přičteme reálný počet bodů),
# rozlišujeme tím mezi 0 a neodevzdaným řešením
# Speciálně pokud jsou body None (hodnocení není obodované), vraťse
i + = 1
# TODO nejde to udělat lépe?
if body is None :
return
if slovnik [ resitel . id ] == " " :
slovnik [ resitel . id ] = 0
slovnik [ resitel . id ] + = body
def secti_body_za_rocnik ( za , aktivni_resitele , jen_verejne ) :
""" Spočítá body za ročník (celý nebo do daného čísla),
setřídí je sestupně a vrátí jako seznam .
Parametry :
za ( typu Rocnik nebo Cislo ) spočítá za ročník , nebo za ročník až do
daného čísla
"""
# spočítáme všem řešitelům jejich body za ročník (False => ne odjakživa)
resitel_rocnikbody_slov = body_resitelu ( aktivni_resitele , za , False , jen_verejne = jen_verejne )
# 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
def secti_body_za_cislo ( cislo , aktivni_resitele , hlavni_problemy = None ) :
""" Spočítá u řešitelů body za číslo a za jednotlivé hlavní problémy (témata). """
# 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ů)
print ( " Scitam cislo " , cislo )
if hlavni_problemy is None :
hlavni_problemy = hlavni_problemy_f ( problemy_cisla ( cislo ) )
def ne_clanek_ne_konfera ( problem ) :
inst = problem . get_real_instance ( )
return not ( isinstance ( inst , m . Clanek ) or isinstance ( inst , m . Konfera ) )
if cislo . rocnik . rocnik < ROCNIK_ZRUSENI_TEMAT :
temata_a_spol = hlavni_problemy
else :
temata_a_spol = list ( filter ( ne_clanek_ne_konfera , hlavni_problemy ) )
hlavni_problemy_slovnik = { }
return radky_vysledkovky
for hp in temata_a_spol :
class VysledkovkaCisla ( Vysledkovka ) :
def __init__ (
self ,
cislo : m . Cislo ,
jen_verejne : bool = True ,
do_deadlinu : m . Deadline = None
) :
self . cislo = cislo
self . rocnik = cislo . rocnik
self . jen_verejne = jen_verejne
if do_deadlinu is None :
do_deadlinu = m . Deadline . objects . filter ( cislo = cislo ) . last ( )
self . do_deadlinu = do_deadlinu
@cached_property
def aktivni_resitele ( self ) - > list [ m . Resitel ] :
# TODO možná chytřeji vybírat aktivní řešitele
return list ( resi_v_rocniku ( self . rocnik ) )
@cached_property
def problemy ( self ) - > list [ m . Problem ] :
return problemy_cisla ( self . cislo )
@cached_property
def hlavni_problemy ( self ) - > list [ m . Problem ] :
return hlavni_problemy_f ( self . problemy )
@cached_property
def problemy_s_body_za_cislo ( self ) :
hlavni_problemy_slovnik = dict ( )
for hp in self . hlavni_problemy :
hlavni_problemy_slovnik [ hp . id ] = { }
hlavni_problemy_slovnik [ hp . id ] = { }
hlavni_problemy_slovnik [ - 1 ] = { }
hlavni_problemy_slovnik [ - 1 ] = { }
# zakládání prázdných záznamů pro řešitele
# zakládání prázdných záznamů pro řešitele
cislobody = { }
cislobody = { }
for ar in aktivni_resitele :
for ar in self . aktivni_resitele :
# řešitele převedeme na řetězec pomocí unikátního id
# řešitele převedeme na řetězec pomocí unikátního id
cislobody [ ar . id ] = " "
cislobody [ ar . id ] = " "
for hp in temata_a_spol :
for hp in self . temata_a_spol :
slovnik = hlavni_problemy_slovnik [ hp . id ]
slovnik = hlavni_problemy_slovnik [ hp . id ]
slovnik [ ar . id ] = " "
slovnik [ ar . id ] = " "
hlavni_problemy_slovnik [ - 1 ] [ ar . id ] = " "
hlavni_problemy_slovnik [ - 1 ] [ ar . id ] = " "
hodnoceni_do_cisla = m . Hodnoceni . objects . prefetch_related ( ' problem ' , ' reseni ' , ' reseni__resitele ' ) . filter ( cislo_body = cislo )
hodnoceni_do_cisla = m . Hodnoceni . objects . prefetch_related (
' problem ' , ' reseni ' , ' reseni__resitele ' ) . filter ( deadline_body__cislo = self . cislo )
start = time . time ( )
for hodnoceni in hodnoceni_do_cisla :
for hodnoceni in hodnoceni_do_cisla :
prob = hodnoceni . problem
prob = hodnoceni . problem
nadproblem = hlavni_problem ( prob )
nadproblem = hlavni_problem ( prob )
if ne_clanek_ne_konfera ( nadproblem ) :
if self . ne_clanek_ne_konfera ( nadproblem ) :
nadproblem_slovnik = hlavni_problemy_slovnik [ nadproblem . id ]
nadproblem_slovnik = hlavni_problemy_slovnik [ nadproblem . id ]
else :
else :
nadproblem_slovnik = hlavni_problemy_slovnik [ - 1 ]
nadproblem_slovnik = hlavni_problemy_slovnik [ - 1 ]
@ -301,45 +280,74 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None):
# a mít více řešitelů
# a mít více řešitelů
for resitel in hodnoceni . reseni . resitele . all ( ) :
for resitel in hodnoceni . reseni . resitele . all ( ) :
if resitel not in aktivni_resitele :
if resitel not in self . aktivni_resitele :
print ( " Skipping {} " . format ( resitel . id ) )
continue
continue
pricti_body ( cislobody , resitel , body )
self . pricti_body ( cislobody , resitel , body )
pricti_body ( nadproblem_slovnik , resitel , body )
self . pricti_body ( nadproblem_slovnik , resitel , body )
end = time . time ( )
print ( " for cykly: " , end - start )
return hlavni_problemy_slovnik , cislobody
return hlavni_problemy_slovnik , cislobody
@cached_property
def hlavni_problemy_slovnik ( self ) - > dict [ int , dict [ int , str ] ] :
return self . problemy_s_body_za_cislo [ 0 ]
def secti_body_za_cislo_podle_temat ( cislo , aktivni_resitele , podproblemy = None , temata = None ) :
@cached_property
""" Spočítá u řešitelů body za číslo za úlohy v jednotlivých hlavních problémech (témata). """
def body_za_cislo ( self ) - > dict [ int , str ] :
if temata is None :
return self . problemy_s_body_za_cislo [ 1 ]
temata = hlavni_problemy_f ( problemy_cisla ( cislo ) )
if podproblemy is None :
@cached_property
podproblemy_v_cislu ( cislo , hlavni_problemy = temata )
def temata_a_spol ( self ) - > list [ m . Problem ] :
if self . cislo . rocnik . rocnik < ROCNIK_ZRUSENI_TEMAT :
return self . hlavni_problemy
else :
return list ( filter ( self . ne_clanek_ne_konfera , self . hlavni_problemy ) )
@cached_property
def je_nejake_ostatni ( self ) :
return len ( self . hlavni_problemy ) - len ( self . temata_a_spol ) > 0
@cached_property
def podproblemy ( self ) - > list [ list [ m . Problem ] ] :
return podproblemy_v_cislu ( self . cislo , self . problemy , self . temata_a_spol )
@cached_property
def podproblemy_seznam ( self ) - > list [ list [ m . Problem ] ] :
return [ self . podproblemy [ it . id ] for it in self . temata_a_spol ] + [ self . podproblemy [ - 1 ] ]
@cached_property
def podproblemy_iter ( self ) - > FixedIterator :
return FixedIterator ( self . podproblemy_seznam . __iter__ ( ) )
@cached_property
def problemy_slovnik ( self ) :
# získáme body u jednotlivých témat
""" Spočítá u řešitelů body za číslo za úlohy v jednotlivých hlavních
problémech ( témata ) . """
body_slovnik = { }
body_slovnik = { }
for tema in temata :
for tema in self . temata_a_spol :
body_slovnik [ tema . id ] = { }
body_slovnik [ tema . id ] = { }
for problem in podproblemy [ tema . id ] :
for problem in self . podproblemy [ tema . id ] :
body_slovnik [ tema . id ] [ problem . id ] = { }
body_slovnik [ tema . id ] [ problem . id ] = { }
body_slovnik [ - 1 ] = { }
body_slovnik [ - 1 ] = { }
for problem in podproblemy [ - 1 ] :
for problem in self . podproblemy [ - 1 ] :
body_slovnik [ - 1 ] [ problem . id ] = { }
body_slovnik [ - 1 ] [ problem . id ] = { }
# zakládání prázdných záznamů pro řešitele
# zakládání prázdných záznamů pro řešitele
for ar in aktivni_resitele :
for ar in self . aktivni_resitele :
for tema in temata :
for tema in self . temata_a_spol :
for problem in podproblemy [ tema . id ] :
for problem in self . podproblemy [ tema . id ] :
body_slovnik [ tema . id ] [ problem . id ] [ ar . id ] = " "
body_slovnik [ tema . id ] [ problem . id ] [ ar . id ] = " "
for problem in podproblemy [ - 1 ] :
for problem in self . podproblemy [ - 1 ] :
body_slovnik [ - 1 ] [ problem . id ] [ ar . id ] = " "
body_slovnik [ - 1 ] [ problem . id ] [ ar . id ] = " "
temata = set ( t . id for t in temata )
temata = set ( t . id for t in self . temata_a_spol )
hodnoceni_do_cisla = m . Hodnoceni . objects . prefetch_related ( ' problem ' , ' reseni ' , ' reseni__resitele ' ) . filter ( cislo_body = cislo )
hodnoceni = m . Hodnoceni . objects . prefetch_related (
' problem ' , ' reseni ' , ' reseni__resitele ' )
if self . jen_verejne :
hodnoceni = hodnoceni . filter ( deadline_body__verejna_vysledkovka = True )
hodnoceni_do_cisla = hodnoceni . filter ( deadline_body__cislo = self . cislo )
for hodnoceni in hodnoceni_do_cisla :
for hodnoceni in hodnoceni_do_cisla :
prob = hodnoceni . problem
prob = hodnoceni . problem
@ -355,108 +363,89 @@ def secti_body_za_cislo_podle_temat(cislo, aktivni_resitele, podproblemy=None, t
# a mít více řešitelů
# a mít více řešitelů
for resitel in hodnoceni . reseni . resitele . all ( ) :
for resitel in hodnoceni . reseni . resitele . all ( ) :
if resitel not in aktivni_resitele :
if resitel not in self . aktivni_resitele :
print ( " Skipping {} " . format ( resitel . id ) )
continue
continue
pricti_body ( problem_slovnik , resitel , body )
self . pricti_body ( problem_slovnik , resitel , body )
return body_slovnik
return body_slovnik
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 ) . """
# TODELETE
def __init__ ( self , poradi , resitel , body_hlavni_problemy_seznam , body_cislo , body_rocnik , body_odjakziva , rok , body_podproblemy , body_podproblemy_iter ) :
class FixedIterator :
self . resitel = resitel
def next ( self ) :
self . rocnik_resitele = resitel . rocnik ( rok )
return self . niter . __next__ ( )
self . body_cislo = body_cislo
self . body_rocnik = body_rocnik
def __init__ ( self , niter ) :
self . body_celkem_odjakziva = body_odjakziva
self . niter = niter
self . poradi = poradi
# TODELETE
self . body_hlavni_problemy_seznam = body_hlavni_problemy_seznam
self . titul = resitel . get_titul ( body_odjakziva )
self . body_podproblemy = body_podproblemy
def data_vysledkovky_cisla ( cislo ) :
self . body_podproblemy_iter = body_podproblemy_iter
problemy = problemy_cisla ( cislo )
hlavni_problemy = hlavni_problemy_f ( problemy )
## 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 ( resi_v_rocniku ( cislo . rocnik ) )
# získáme body za číslo
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 , jen_verejne = True )
# získáme body odjakživa
resitel_odjakzivabody_slov = body_resitelu ( aktivni_resitele , cislo , jen_verejne = True )
# řešitelé setřídění podle bodů za číslo sestupně
setrizeni_resitele_id = [ dvojice [ 0 ] for dvojice in resitel_rocnikbody_sezn ]
# spočítáme pořadí řešitelů
setrizeni_resitele_body = [ dvojice [ 1 ] for dvojice in resitel_rocnikbody_sezn ]
poradi = sloupec_s_poradim ( setrizeni_resitele_body )
@cached_property
def radky_vysledkovky ( self ) - > list [ RadekVysledkovkyCisla ] :
# vytvoříme jednotlivé sloupce výsledkovky
# vytvoříme jednotlivé sloupce výsledkovky
radky_vysledkovky = [ ]
radky_vysledkovky = [ ]
i = 0
i = 0
def ne_clanek_ne_konfera ( problem ) :
return not ( isinstance ( problem . get_real_instance ( ) , m . Clanek ) or isinstance ( problem . get_real_instance ( ) , m . Konfera ) )
if cislo . rocnik . rocnik < ROCNIK_ZRUSENI_TEMAT :
temata_a_spol = hlavni_problemy
else :
temata_a_spol = list ( filter ( ne_clanek_ne_konfera , hlavni_problemy ) )
# získáme body u jednotlivých témat
podproblemy = podproblemy_v_cislu ( cislo , problemy , temata_a_spol )
problemy_slovnik = secti_body_za_cislo_podle_temat ( cislo , aktivni_resitele , podproblemy , temata_a_spol )
# def not_empty(value):
# return value != ''
#
# je_nejake_ostatni = any(filter(not_empty, hlavni_problemy_slovnik[-1].values())) > 0
je_nejake_ostatni = len ( hlavni_problemy ) - len ( temata_a_spol ) > 0
setrizeni_resitele_slovnik = { }
setrizeni_resitele_slovnik = { }
setrizeni_resitele = m . Resitel . objects . filter ( id__in = setrizeni_resitele_id ) . select_related ( ' osoba ' )
setrizeni_resitele = m . Resitel . objects . filter ( id__in = self . setrizeni_resitele_id ) . select_related ( ' osoba ' )
for r in setrizeni_resitele :
for r in setrizeni_resitele :
setrizeni_resitele_slovnik [ r . id ] = r
setrizeni_resitele_slovnik [ r . id ] = r
for ar_id in setrizeni_resitele_id :
for ar_id in self . setrizeni_resitele_id :
if self . setrizene_body [ i ] > 0 :
# získáme seznam bodů za problémy pro daného řešitele
# získáme seznam bodů za problémy pro daného řešitele
body_problemy = [ ]
body_problemy = [ ]
body_podproblemy = [ ]
body_podproblemy = [ ]
for hp in temata_a_spol :
for hp in self . temata_a_spol :
body_problemy . append ( hlavni_problemy_slovnik [ hp . id ] [ ar_id ] )
body_problemy . append ( self . hlavni_problemy_slovnik [ hp . id ] [ ar_id ] )
body_podproblemy . append ( [ problemy_slovnik [ hp . id ] [ it . id ] [ ar_id ] for it in podproblemy [ hp . id ] ] )
body_podproblemy . append ( [
if je_nejake_ostatni :
self . problemy_slovnik [ hp . id ] [ it . id ] [ ar_id ]
body_problemy . append ( hlavni_problemy_slovnik [ - 1 ] [ ar_id ] )
for it in self . podproblemy [ hp . id ]
body_podproblemy . append ( [ problemy_slovnik [ - 1 ] [ it . id ] [ ar_id ] for it in podproblemy [ - 1 ] ] )
] )
if self . je_nejake_ostatni :
body_problemy . append ( self . hlavni_problemy_slovnik [ - 1 ] [ ar_id ] )
body_podproblemy . append (
[ self . problemy_slovnik [ - 1 ] [ it . id ] [ ar_id ] for it in self . podproblemy [ - 1 ] ] )
# vytáhneme informace pro daného řešitele
# vytáhneme informace pro daného řešitele
radek = RadekVysledkovkyCisla (
radek = self . RadekVysledkovkyCisla (
poradi [ i ] , # pořadí
poradi = self . poradi [ i ] ,
setrizeni_resitele_slovnik [ ar_id ] , # řešitel (z id)
resitel = setrizeni_resitele_slovnik [ ar_id ] ,
body_problemy , # seznam bodů za hlavní problémy čísla
body_hlavni_problemy_seznam = body_problemy ,
cislobody [ ar_id ] , # body za číslo
body_cislo = self . body_za_cislo [ ar_id ] ,
setrizeni_resitel e_body[ i ] , # body za ročník (spočítané výše s pořadím)
body_rocnik = self . setrizen e_body [ i ] ,
resitel_odjakzivabody_slov [ ar_id ] , # body odjakživa
body_odjakziva = self . resitel_body_odjakziva_slovnik [ ar_id ] ,
cislo . rocnik ,
rok = self . rocnik ,
body_podproblemy , # body všech podproblémů
body_podproblemy = body_podproblemy , # body všech podproblémů
FixedIterator ( body_podproblemy . __iter__ ( ) ) # TODELETE
body_podproblemy_iter = FixedIterator ( body_podproblemy . __iter__ ( ) )
) # ročník semináře pro zjištění ročníku řešitele
) # ročník semináře pro zjištění ročníku řešitele
radky_vysledkovky . append ( radek )
radky_vysledkovky . append ( radek )
i + = 1
i + = 1
return radky_vysledkovky
# vytahané informace předáváme do kontextu
@staticmethod
pt = [ podproblemy [ it . id ] for it in temata_a_spol ] + [ podproblemy [ - 1 ] ]
def pricti_body ( slovnik , resitel , body ) :
radky_vysledkovky = [ radek for radek in radky_vysledkovky if radek . body_rocnik > 0 ]
""" Přiřazuje danému řešiteli body do slovníku. """
return (
# testujeme na None (""), pokud je to první řešení
radky_vysledkovky ,
# daného řešitele, předěláme na 0
temata_a_spol ,
# (v dalším kroku přičteme reálný počet bodů),
je_nejake_ostatni ,
# rozlišujeme tím mezi 0 a neodevzdaným řešením
pt ,
FixedIterator ( pt . __iter__ ( ) )
# Speciálně pokud jsou body None (hodnocení není obodované), vraťse
)
# TODO nejde to udělat lépe?
if body is None :
return
if slovnik [ resitel . id ] == " " :
slovnik [ resitel . id ] = 0
slovnik [ resitel . id ] + = body
@staticmethod
def ne_clanek_ne_konfera ( problem ) :
inst = problem . get_real_instance ( )
return not ( isinstance ( inst , m . Clanek ) or isinstance ( inst , m . Konfera ) )