Browse Source

Merge branch 'data_migrations' into treenode_editor

export_seznamu_prednasek
parent
commit
b977a44344
  1. 4
      galerie/models.py
  2. 16
      mamweb/static/css/mamweb.css
  3. 2
      mamweb/templates/graph.svg
  4. 139
      seminar/testutils.py
  5. 183
      seminar/views/views_all.py

4
galerie/models.py

@ -39,8 +39,8 @@ def obrazek_filename(self, filename):
# soustředění je v cestě jen pokud galerie pod nějaké patří # soustředění je v cestě jen pokud galerie pod nějaké patří
cesta = ( cesta = (
['Galerie'] + ['Galerie'] +
(["soustredeni_" + gal.soustredeni.pk] if gal.soustredeni else []) + (["soustredeni_{}".format(gal.soustredeni.pk)] if gal.soustredeni else []) +
["galerie_" + cislo_gal, self.nazev] ["galerie_{}".format(cislo_gal), self.nazev]
) )
return os.path.join(*cesta) return os.path.join(*cesta)

16
mamweb/static/css/mamweb.css

@ -242,6 +242,10 @@ nav.nav-button {
display: none; display: none;
} }
div.dropdown-backdrop { /* tohle způsobuje, že funguje mobilní menu */
z-index: -1;
}
h1 a:hover { h1 a:hover {
text-decoration: none; text-decoration: none;
} }
@ -387,10 +391,15 @@ p.license-mobile {
} }
div.graf{ div.graf{
width: 70%;
float: none; float: none;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
width: 70%; margin-top: 10px;
}
#svg-graf{
width: 100%;
height: auto;;
} }
ul.menu { ul.menu {
@ -576,10 +585,7 @@ ul.submenu {
} }
div.graf { div.graf {
float: none; width: 100%;
width: 70%;
margin-left: auto;
margin-right: auto;
} }
} }

2
mamweb/templates/graph.svg

@ -10,7 +10,7 @@
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1" version="1.1"
id="svg2" id="svg-graf"
width="482.57019" width="482.57019"
height="599.45636" height="599.45636"
viewBox="0 0 482.57019 599.45636" viewBox="0 0 482.57019 599.45636"

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

139
seminar/testutils.py

@ -176,10 +176,9 @@ def gen_organizatori(rnd, osoby, last_rocnik, users):
organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga)) organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga))
return organizatori return organizatori
def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size): def gen_zadani_ulohy(rnd, cisla, organizatori, pocet_oboru, poradi_cisla, poradi_problemu):
logger.info('Generuji úlohy do čísla (size={})...'.format(size))
# ulohy resene v cisle # Proměnné pro náhodné generování názvů a zadání.
jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá", jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá",
"Zákeřná", "Fyzikální"] "Zákeřná", "Fyzikální"]
co = ["kostka", "smršť", "díra", "zrada", "toulka", "tyč", co = ["kostka", "smršť", "díra", "zrada", "toulka", "tyč",
@ -189,43 +188,20 @@ def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size)
ceho = ["všech", "správných", "konstatních", "zelených"] ceho = ["všech", "správných", "konstatních", "zelených"]
jmeno = ["řešení", "tahů", "čísel", "kalhot", "koulí", "hadů"] jmeno = ["řešení", "tahů", "čísel", "kalhot", "koulí", "hadů"]
kde = ["na zemi", "ve vesmíru", "ve vzduchu", "na šňůře", "v letadle"] kde = ["na zemi", "ve vesmíru", "ve vzduchu", "na šňůře", "v letadle"]
obor = ["M", "F", "I", "O", "B"] obory = ["M", "F", "I", "O", "B"]
reseni = ["to je přece jasné", "triviální", "omlouváme se,"
"otevřený problém", "neřešitelné", "triviálně triviální",
"použitím věty z prvního semestru na matfyzu",
"jednoduše pomocí látky z druhého semestru na matfyzu",
"netriviální aplikace diferenciálních rovnic", "zadání je vnitřně"
"sporné", "nepopsatelně jednoduché", "pokud jste na to nepřišli,"
"tak jste fakt hloupí"]
k = 0
for rocnik in rocniky:
k+=1
print("Generuji {}. číslo.".format(k))
cisla = rocnik_cisla[k-1]
for ci in range(3, len(cisla)+1): # pro všechna čísla
resitele_size = round(7/8 * 30 * size) # očekáváný celkový počet řešitelů
poc_res = rnd.randint(round(resitele_size/8), round(resitele_size/4))
# dané číslo řeší něco mezi osminou a čtvrtinou všech řešitelů
# (náhodná hausnumera, možno změnit)
# účelem je, aby se řešení generovala z menší množiny řešitelů a tedy
# bylo více řešení od jednoho řešitele daného čísla
resitele_cisla = rnd.sample(resitele, poc_res)
for pi in range(1, ((size + 1) // 2) + 1):
poc_op = rnd.randint(1, 4) # počet opravovatelů
poc_oboru = rnd.randint(1, 2)
p = Uloha.objects.create( p = Uloha.objects.create(
# atributy třídy Problem # atributy třídy Problem
nazev=" ".join([rnd.choice(jaka), rnd.choice(co)]), nazev=" ".join([rnd.choice(jaka), rnd.choice(co)]),
stav=Problem.STAV_ZADANY, stav=Problem.STAV_ZADANY,
zamereni=rnd.sample(["M", "F", "I", "O", "B"], poc_oboru), zamereni=rnd.sample(obory, pocet_oboru),
autor=rnd.choice(organizatori), autor=rnd.choice(organizatori),
garant=rnd.choice(organizatori), garant=rnd.choice(organizatori),
kod=str(pi), kod=str(poradi_problemu),
# atributy třídy Uloha # atributy třídy Uloha
cislo_zadani=cisla[ci-2-1], cislo_zadani=cisla[poradi_cisla-2-1],
cislo_reseni=cisla[ci-1], cislo_reseni=cisla[poradi_cisla-1],
cislo_deadline=cisla[ci-1], cislo_deadline=cisla[poradi_cisla-1],
max_body = rnd.randint(1, 8) max_body = rnd.randint(1, 8)
) )
@ -248,45 +224,93 @@ def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size)
zad = TextNode.objects.create(text = text_zadani) zad = TextNode.objects.create(text = text_zadani)
uloha_zadani = UlohaZadaniNode.objects.create(uloha = p, first_child = zad) uloha_zadani = UlohaZadaniNode.objects.create(uloha = p, first_child = zad)
p.ulohazadaninode = uloha_zadani p.ulohazadaninode = uloha_zadani
otec_syn(cisla[ci-2-1].cislonode, uloha_zadani) otec_syn(cisla[poradi_cisla-2-1].cislonode, uloha_zadani)
return p
def gen_vzoroveho_reseni_ulohy(rnd, cisla, organizatori, uloha, pocet_opravovatelu, poradi_cisla):
reseni = ["to je přece jasné", "triviální", "omlouváme se,"
"otevřený problém", "neřešitelné", "triviálně triviální",
"použitím věty z prvního semestru na matfyzu",
"jednoduše pomocí látky z druhého semestru na matfyzu",
"netriviální aplikace diferenciálních rovnic", "zadání je vnitřně"
"sporné", "nepopsatelně jednoduché", "pokud jste na to nepřišli,"
"tak jste fakt hloupí"]
# generování vzorového textu # Generování vzorového řešení.
text_vzoraku = Text.objects.create( text_vzoraku = Text.objects.create(
na_web = rnd.choice(reseni), na_web = rnd.choice(reseni),
do_cisla = rnd.choice(reseni) do_cisla = rnd.choice(reseni)
) )
vzorak = TextNode.objects.create(text = text_vzoraku) vzorak = TextNode.objects.create(text = text_vzoraku)
uloha_vzorak = UlohaVzorakNode.objects.create(uloha=p, first_child = vzorak) uloha_vzorak = UlohaVzorakNode.objects.create(uloha = uloha, first_child = vzorak)
p.ulohavzoraknode = uloha_vzorak uloha.ulohavzoraknode = uloha_vzorak
otec_syn(cisla[ci-1].cislonode, uloha_vzorak) otec_syn(cisla[poradi_cisla-1].cislonode, uloha_vzorak)
uloha.opravovatele.set(rnd.sample(organizatori, pocet_opravovatelu))
uloha.save()
return
p.opravovatele.set(rnd.sample(organizatori,poc_op)) def gen_reseni_ulohy(rnd, cisla, uloha, pocet_resitelu, poradi_cisla, resitele_cisla, resitele):
p.save()
# generování řešení pocet_reseni = rnd.randint(pocet_resitelu//4, pocet_resitelu * 4)
poc_reseni = rnd.randint(poc_res, poc_res * 4)
# generujeme náhodný počet řešení vzhledem k počtu řešitelů čísla # generujeme náhodný počet řešení vzhledem k počtu řešitelů čísla
for ri in range(poc_reseni): for _ in range(pocet_reseni):
#print("Generuji {}-té řešení".format(ri)) #print("Generuji {}-té řešení".format(reseni))
if rnd.randint(1, 10) == 6: if rnd.randint(1, 10) == 1:
# cca desetina řešení od více řešitelů # cca desetina řešení od více řešitelů
res_vyber = rnd.sample(resitele_cisla, res_vyber = rnd.sample(resitele_cisla,
rnd.randint(2, 5)) rnd.randint(2, 5))
else: else:
res_vyber = rnd.sample(resitele_cisla, 1) res_vyber = rnd.sample(resitele_cisla, 1)
if resitele[0] in res_vyber: if resitele[0] in res_vyber: # speciální řešitel, který nemá žádné body
res_vyber.remove(resitele[0]) res_vyber.remove(resitele[0])
# Vytvoření řešení.
res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0]) res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0])
# problem a resitele přiřadíme později, ManyToManyField # Problím a řešitele přiřadíme později, ManyToManyField
# se nedá vyplnit v create() # se nedá vyplnit v create().
res.resitele.set(res_vyber) res.resitele.set(res_vyber)
res.save() res.save()
# Vytvoření hodnocení.
hod = Hodnoceni.objects.create( hod = Hodnoceni.objects.create(
body=rnd.randint(0, p.max_body), body=rnd.randint(0, uloha.max_body),
cislo_body=cisla[ci-1], cislo_body=cisla[poradi_cisla - 1],
reseni=res, reseni=res,
problem=p problem=uloha
) )
return
def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size):
logger.info('Generuji úlohy do čísla (size={})...'.format(size))
k = 0
for rocnik in rocniky:
k += 1
print("Generuji {}. číslo.".format(k))
cisla = rocnik_cisla[k - 1]
for ci in range(3, len(cisla) + 1): # pro všechna čísla
resitele_size = round(7/8 * 30 * size) # očekáváný celkový počet řešitelů
poc_res = rnd.randint(resitele_size//8, resitele_size//4)
# dané číslo řeší něco mezi osminou a čtvrtinou všech řešitelů
# (náhodná hausnumera, možno změnit)
# účelem je, aby se řešení generovala z menší množiny řešitelů a tedy
# bylo více řešení od jednoho řešitele daného čísla
resitele_cisla = rnd.sample(resitele, poc_res)
for pi in range(1, ((size + 1) // 2) + 1): # počet problémů
poc_op = rnd.randint(1, 4) # počet opravovatelů
poc_oboru = rnd.randint(1, 2)
# Generování zadání úlohy a UlohaZadaniNode,
# přivěšení pod dané číslo
p = gen_zadani_ulohy(rnd, cisla, organizatori, poc_oboru, ci, pi)
# Generování vzorového řešení
gen_vzoroveho_reseni_ulohy(rnd, cisla, organizatori, p, poc_op, ci)
# Generování řešení a hodnocení k úloze
gen_reseni_ulohy(rnd, cisla, p, poc_res, ci,
resitele_cisla, resitele)
return return
@ -482,8 +506,10 @@ def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori)
rocnik=rocnik, rocnik=rocnik,
poradi=str(int(cislo.poradi) + 2), poradi=str(int(cislo.poradi) + 2),
) )
# Pokud není číslo pro vzorák, tak se dá do posledního čísla (i kdyby tam mělo být zadání i řešení...) # Pokud není číslo pro vzorák, tak se dá do posledního čísla
# Tohle sice umožňuje vygenerovat vzorák do čísla dávno po konci témátka, ale to nám pro jednoduchost nevadí. # (i kdyby tam mělo být zadání i řešení...)
# Tohle sice umožňuje vygenerovat vzorák do čísla dávno po konci témátka,
# ale to nám pro jednoduchost nevadí.
if len(cislo_se_vzorakem) == 0: if len(cislo_se_vzorakem) == 0:
cislo_se_vzorakem = cisla[-1] cislo_se_vzorakem = cisla[-1]
else: else:
@ -505,7 +531,8 @@ def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori)
tema = tema_node.tema tema = tema_node.tema
# Pokud už témátko skončilo, žádné úložky negenerujeme # Pokud už témátko skončilo, žádné úložky negenerujeme
# FIXME: Bylo by hezčí, kdyby se čísla předávala jako Cislo a ne jako int v té trojici (start, konec, tema) # FIXME: Bylo by hezčí, kdyby se čísla předávala jako Cislo a ne
# jako int v té trojici (start, konec, tema)
if not temata[int(tema.kod)-1][1] >= int(cislo_se_vzorakem.poradi): if not temata[int(tema.kod)-1][1] >= int(cislo_se_vzorakem.poradi):
continue continue
@ -581,8 +608,10 @@ def gen_novinky(rnd, organizatori):
kdy = ["Zítra bude", "10. 10. 2020 bude", "V prosinci bude", "V létě bude"] kdy = ["Zítra bude", "10. 10. 2020 bude", "V prosinci bude", "V létě bude"]
for i in range(5): for i in range(5):
text_novinky = " ".join([rnd.choice(kdy),rnd.choice(kde),rnd.choice(jake),rnd.choice(co)]) text_novinky = " ".join([rnd.choice(kdy), rnd.choice(kde), rnd.choice(jake),
novinka = Novinky.objects.create(id=i,autor=rnd.choice(organizatori),text=(text_novinky+", těšíme se na vás!"),zverejneno=rnd.choice([True,False])) rnd.choice(co)])
novinka = Novinky.objects.create(id=i,autor=rnd.choice(organizatori),
text=(text_novinky+", těšíme se na vás!"),zverejneno=rnd.choice([True,False]))
novinka.save() novinka.save()
return return

183
seminar/views/views_all.py

@ -387,10 +387,16 @@ class ArchivView(generic.ListView):
### Výsledky ### Výsledky
# 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): 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:
sloupec_s_poradim (seznam stringů)
"""
# 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
@ -421,20 +427,28 @@ def sloupec_s_poradim(setrizene_body):
aktualni_poradi = aktualni_poradi + velikost_skupiny aktualni_poradi = aktualni_poradi + velikost_skupiny
return sloupec_s_poradim return sloupec_s_poradim
# vrátí všechna čísla daného ročníku
def cisla_rocniku(rocnik, jen_verejne=True): def cisla_rocniku(rocnik, jen_verejne=True):
""" Vrátí všechna čísla daného ročníku.
Parametry:
rocnik (Rocnik): ročník semináře
jen_verejne (bool): zda se mají vrátit jen veřejná, nebo všechna čísla
Vrátí:
seznam objektů typu Cislo
"""
if jen_verejne: if jen_verejne:
return rocnik.verejna_cisla() return rocnik.verejna_cisla()
else: else:
return rocnik.cisla.all() return rocnik.cisla.all()
# pro daný problém vrátí jeho nejvyšší nadproblém
def hlavni_problem(problem): def hlavni_problem(problem):
""" Pro daný problém vrátí jeho nejvyšší nadproblém."""
while not(problem.nadproblem == None): while not(problem.nadproblem == None):
problem = problem.nadproblem problem = problem.nadproblem
return problem return problem
def hlavni_problemy_rocniku(rocnik, jen_verejne=True): def hlavni_problemy_rocniku(rocnik, jen_verejne=True):
""" Pro zadaný ročník vrátí hlavní problémy ročníku,
tj. ty, které nemají nadproblém."""
hlavni_problemy = [] hlavni_problemy = []
for cislo in cisla_rocniku(rocnik, jen_verejne): for cislo in cisla_rocniku(rocnik, jen_verejne):
for problem in hlavni_problemy_cisla(cislo): for problem in hlavni_problemy_cisla(cislo):
@ -445,8 +459,8 @@ def hlavni_problemy_rocniku(rocnik, jen_verejne=True):
return hlavni_problemy 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): def hlavni_problemy_cisla(cislo):
""" Vrátí seznam všech problémů s body v daném čísle, které již nemají nadproblém. """
hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all() hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all()
# hodnocení, která se vážou k danému číslu # hodnocení, která se vážou k danému číslu
@ -468,33 +482,68 @@ def hlavni_problemy_cisla(cislo):
return hlavni_problemy return hlavni_problemy
# vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník def body_resitelu(resitele, za, odjakziva=True):
def body_resitelu_odjakziva(rocnik, resitele): """ Funkce počítající počty bodů pro zadané řešitele,
buď odjakživa do daného ročníku/čísla anebo za daný ročník/číslo.
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, Rocnik):
cislo = None
rocnik = za
rok = rocnik.prvni_rok
elif isinstance(za, 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=cislo) ))
elif rocnik and odjakziva: # Spočítáme body za starší ročníky až do zadaného včetně.
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.
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ů # Následující řádek přidá ke každému řešiteli údaj ".body" se součtem jejich bodů
resitele_s_body = Resitel.objects.annotate(body=Sum('reseni__hodnoceni__body')) resitele_s_body = Resitel.objects.filter(id__in=resitele_id).annotate(
# Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník indexovaný řešitelským id obsahující body body=body_k_zapocteni)
# ... ale jen ro řešitele, které dostaneme jako parametr. # Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník
# TODO: Zjistit, co ten parametr říká a proč je potřeba # indexovaný řešitelským id obsahující body.
body_odjakziva = {int(res.id) : res.body for res in resitele_s_body if res in resitele} # Pokud jsou body None, nahradíme za 0.
return body_odjakziva slovnik = {int(res.id) : (res.body if res.body else 0) for res in resitele_s_body}
return slovnik
# vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník
def body_resitelu_za_rocnik(rocnik, aktivni_resitele):
body_za_rocnik = {}
# inicializujeme na 0 pro všechny aktivní řešitele
for ar in aktivni_resitele:
body_za_rocnik[ar.id] = 0
# spočítáme body řešitelům přes všechna řešení s hodnocením v daném ročníku
print("Před dotazem:{}".format(time.time()))
reseni = Reseni.objects.prefetch_related('resitele', 'hodnoceni_set').filter(hodnoceni__cislo_body__rocnik=rocnik)
print("Po dotazu:{}".format(time.time()))
for res in reseni:
for resitel in res.resitele.all():
for hodn in res.hodnoceni_set.all():
pricti_body(body_za_rocnik, resitel, hodn.body)
print("Po for-cyklu:{}".format(time.time()))
return body_za_rocnik
class RadekVysledkovkyRocniku(object): class RadekVysledkovkyRocniku(object):
""" 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.
@ -523,7 +572,6 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik) #.filter(hodnoceni_set__rocnik__eq=cislo_rocnik)
cisla = cisla_rocniku(rocnik, jen_verejne) cisla = cisla_rocniku(rocnik, jen_verejne)
body_cisla_slov = {} body_cisla_slov = {}
print("Jen veřejná: {}, čísla: {}".format(jen_verejne, cisla))
for cislo in cisla: for cislo in cisla:
# získáme body za číslo # získáme body za číslo
_, cislobody = secti_body_za_cislo(cislo, aktivni_resitele) _, cislobody = secti_body_za_cislo(cislo, aktivni_resitele)
@ -539,7 +587,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
poradi = sloupec_s_poradim(setrizene_body) poradi = sloupec_s_poradim(setrizene_body)
# získáme body odjakživa # získáme body odjakživa
resitel_odjakzivabody_slov = body_resitelu_odjakziva(rocnik, aktivni_resitele) resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, rocnik)
# vytvoříme jednotlivé sloupce výsledkovky # vytvoříme jednotlivé sloupce výsledkovky
radky_vysledkovky = [] radky_vysledkovky = []
@ -558,11 +606,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
setrizene_body[i], # body za ročník (spočítané výše s pořadím) setrizene_body[i], # body za ročník (spočítané výše s pořadím)
resitel_odjakzivabody_slov[ar_id], # body odjakživa resitel_odjakzivabody_slov[ar_id], # body odjakživa
rocnik) # ročník semináře pro získání ročníku řešitele rocnik) # ročník semináře pro získání ročníku řešitele
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) radky_vysledkovky.append(radek)
print("Přikládám {}-tý řádek.".format(i))
i += 1 i += 1
return radky_vysledkovky return radky_vysledkovky
@ -618,8 +662,8 @@ class RadekVysledkovkyCisla(object):
self.titul = resitel.get_titul(body_odjakziva) self.titul = resitel.get_titul(body_odjakziva)
# přiřazuje danému řešiteli body do slovníku
def pricti_body(slovnik, resitel, body): 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í # testujeme na None (""), pokud je to první řešení
# daného řešitele, předěláme na 0 # daného řešitele, předěláme na 0
# (v dalším kroku přičteme reálný počet bodů), # (v dalším kroku přičteme reálný počet bodů),
@ -630,15 +674,16 @@ def pricti_body(slovnik, resitel, body):
slovnik[resitel.id] += body slovnik[resitel.id] += body
def secti_body_za_rocnik(rocnik, aktivni_resitele): def secti_body_za_rocnik(rocnik, aktivni_resitele):
# spočítáme všem řešitelům jejich body za ročník """ Spočítá body za ročník, setřídí je sestupně a vrátí jako seznam."""
resitel_rocnikbody_slov = body_resitelu_za_rocnik(rocnik, aktivni_resitele) # 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, rocnik, False)
# zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně # 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(), resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(),
key = lambda x: x[1], reverse = True) key = lambda x: x[1], reverse = True)
return resitel_rocnikbody_sezn 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=None): 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é # 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 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ů) # pro jednotlivé řešitele (slovník slovníků hlavních problémů)
@ -701,8 +746,7 @@ def vysledkovka_cisla(cislo, context=None):
resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo.rocnik, aktivni_resitele) resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo.rocnik, aktivni_resitele)
# získáme body odjakživa # získáme body odjakživa
resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik, resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo)
aktivni_resitele)
# řešitelé setřídění podle bodů za číslo sestupně # řešitelé setřídění podle bodů za číslo sestupně
setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn]
@ -729,10 +773,7 @@ def vysledkovka_cisla(cislo, context=None):
setrizeni_resitele_body[i], # body za ročník (spočítané výše s pořadím) setrizeni_resitele_body[i], # body za ročník (spočítané výše s pořadím)
resitel_odjakzivabody_slov[ar_id], # body odjakživa resitel_odjakzivabody_slov[ar_id], # body odjakživa
cislo.rocnik) # ročník semináře pro zjištění ročníku řešitele cislo.rocnik) # ročník semináře pro zjištění ročníku řešitele
print("{}: body za problémy - {}, číslobody - {}, ročníkbody - {}, odjakživabody - {}".format(radek.resitel,
radek.body_problemy_sezn, radek.body_cislo, radek.body_rocnik, radek.body_celkem_odjakziva))
radky_vysledkovky.append(radek) radky_vysledkovky.append(radek)
print("Přikládám {}-tý řádek.".format(i))
i += 1 i += 1
# vytahané informace předáváme do kontextu # vytahané informace předáváme do kontextu
@ -741,7 +782,6 @@ def vysledkovka_cisla(cislo, context=None):
context['problemy'] = hlavni_problemy context['problemy'] = hlavni_problemy
#context['v_cisle_zadane'] = TODO #context['v_cisle_zadane'] = TODO
#context['resene_problemy'] = resene_problemy #context['resene_problemy'] = resene_problemy
print("Předávám kontext.")
return context return context
class CisloView(generic.DetailView): class CisloView(generic.DetailView):
@ -779,7 +819,7 @@ class ArchivTemataView(generic.ListView):
### Generovani vysledkovky ### Generovani vysledkovky
class CisloVysledkovkaView(CisloView): class CisloVysledkovkaView(CisloView):
"View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu." """View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu."""
model = Cislo model = Cislo
template_name = 'seminar/archiv/cislo_vysledkovka.tex' template_name = 'seminar/archiv/cislo_vysledkovka.tex'
@ -789,7 +829,7 @@ class CisloVysledkovkaView(CisloView):
#vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani
class RocnikVysledkovkaView(RocnikView): class RocnikVysledkovkaView(RocnikView):
"View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu." """ View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu."""
model = Rocnik model = Rocnik
template_name = 'seminar/archiv/rocnik_vysledkovka.tex' template_name = 'seminar/archiv/rocnik_vysledkovka.tex'
#content_type = 'application/x-tex; charset=UTF8' #content_type = 'application/x-tex; charset=UTF8'
@ -798,6 +838,7 @@ class RocnikVysledkovkaView(RocnikView):
#vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani
### Generovani obalek ### Generovani obalek
class CisloObalkyStruct: class CisloObalkyStruct:
rocnik = None rocnik = None
cisla = None cisla = None
@ -827,8 +868,10 @@ def aktivniResitele(rocnik,cislo):
if int(cislo) > 3: if int(cislo) > 3:
problemy = Problem.objects.filter(cislo_zadani__in = letos.cisla) problemy = Problem.objects.filter(cislo_zadani__in = letos.cisla)
else: else:
problemy = Problem.objects.filter(Q(cislo_zadani__in = letos.cisla)|Q(cislo_zadani__in = loni.cisla)) problemy = Problem.objects.filter(
resitele = aktualni_resitele.filter(reseni__in = Reseni.objects.filter(problem__in=problemy)).distinct() Q(cislo_zadani__in = letos.cisla) | Q(cislo_zadani__in = loni.cisla) )
resitele = aktualni_resitele.filter(reseni__in = Reseni.objects.filter(
problem__in=problemy)).distinct()
return resitele return resitele
@ -875,13 +918,15 @@ def oldObalkovaniView(request, rocnik, cislo):
### Tituly ### Tituly
def TitulyView(request, rocnik, cislo): def TitulyView(request, rocnik, cislo):
""" View pro stažení makra titulů v TeXu."""
rocnik_obj = Rocnik.objects.get(rocnik = rocnik) rocnik_obj = Rocnik.objects.get(rocnik = rocnik)
resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok) resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok)
cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, poradi = cislo) cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, poradi = cislo)
asciijmena = [] asciijmena = []
jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka), pokud ano, vrátí se jako true jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka),
slovnik_s_body = body_resitelu_odjakziva(rocnik_obj, resitele) # pokud ano, vrátí se jako true
slovnik_s_body = body_resitelu(resitele, rocnik_obj)
for resitel in resitele: for resitel in resitele:
resitel.titul = resitel.get_titul(slovnik_s_body[resitel.id]) resitel.titul = resitel.get_titul(slovnik_s_body[resitel.id])
@ -899,8 +944,6 @@ def TitulyView(request, rocnik, cislo):
return render(request, 'seminar/archiv/tituly.tex', return render(request, 'seminar/archiv/tituly.tex',
{'resitele': resitele,'jmenovci':jmenovci},content_type="text/plain") {'resitele': resitele,'jmenovci':jmenovci},content_type="text/plain")
### Soustredeni ### Soustredeni
class SoustredeniListView(generic.ListView): class SoustredeniListView(generic.ListView):
@ -929,13 +972,13 @@ class SoustredeniUcastniciBaseView(generic.ListView):
class SoustredeniMailyUcastnikuView(SoustredeniUcastniciBaseView): class SoustredeniMailyUcastnikuView(SoustredeniUcastniciBaseView):
"""Seznam e-mailů řešitelů oddělených čárkami""" """ Seznam e-mailů řešitelů oddělených čárkami. """
model = Soustredeni_Ucastnici model = Soustredeni_Ucastnici
template_name = 'seminar/soustredeni/maily_ucastniku.txt' template_name = 'seminar/soustredeni/maily_ucastniku.txt'
class SoustredeniUcastniciView(SoustredeniUcastniciBaseView): class SoustredeniUcastniciView(SoustredeniUcastniciBaseView):
"""HTML tabulka účastníků pro tisk""" """ HTML tabulka účastníků pro tisk. """
model = Soustredeni_Ucastnici model = Soustredeni_Ucastnici
template_name = 'seminar/soustredeni/seznam_ucastniku.html' template_name = 'seminar/soustredeni/seznam_ucastniku.html'
@ -1057,11 +1100,11 @@ def texUploadView(request):
} }
problem_typ = typy[meta["typ"]] problem_typ = typy[meta["typ"]]
# Pokud už problém existuje, vytáhneme jej z db a upravíme # Pokud už problém existuje, vytáhneme jej z db a upravíme.
# Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené # Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené.
# Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> # Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku ->
# číslo/ročník se musí založit ručně v adminu # číslo/ročník se musí založit ručně v adminu.
rocnik = Rocnik.objects.get(rocnik=meta["rocnik"]) rocnik = Rocnik.objects.get(rocnik=meta["rocnik"])
cislo = Cislo.objects.get(rocnik=rocnik, cislo=meta["cislo"]) cislo = Cislo.objects.get(rocnik=rocnik, cislo=meta["cislo"])
@ -1195,7 +1238,8 @@ class ResitelView(LoginRequiredMixin,generic.DetailView):
print(self.request.user) print(self.request.user)
return Resitel.objects.get(osoba__user=self.request.user) return Resitel.objects.get(osoba__user=self.request.user)
## Formulare ### Formulare
class AddSolutionView(LoginRequiredMixin, FormView): class AddSolutionView(LoginRequiredMixin, FormView):
template_name = 'seminar/org/vloz_reseni.html' template_name = 'seminar/org/vloz_reseni.html'
form_class = f.VlozReseniForm form_class = f.VlozReseniForm
@ -1234,9 +1278,6 @@ class SubmitSolutionView(LoginRequiredMixin, CreateView):
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
def resetPasswordView(request): def resetPasswordView(request):
pass pass
@ -1398,10 +1439,6 @@ def prihlaskaView(request):
return render(request, 'seminar/prihlaska.html', {'form': form}) return render(request, 'seminar/prihlaska.html', {'form': form})
# FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar' # FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar'
class LoginView(auth_views.LoginView): class LoginView(auth_views.LoginView):
# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
@ -1419,25 +1456,25 @@ class LogoutView(auth_views.LogoutView):
# Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité. # Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité.
next_page = reverse_lazy('titulni_strana') next_page = reverse_lazy('titulni_strana')
# "Chci resetovat heslo"
class PasswordResetView(auth_views.PasswordResetView): class PasswordResetView(auth_views.PasswordResetView):
""" Chci resetovat heslo. """
#template_name = 'seminar/password_reset.html' #template_name = 'seminar/password_reset.html'
# TODO: vlastní email_template_name a subject_template_name a html_email_template_name # TODO: vlastní email_template_name a subject_template_name a html_email_template_name
success_url = reverse_lazy('reset_password_done') success_url = reverse_lazy('reset_password_done')
from_email = 'login@mam.mff.cuni.cz' from_email = 'login@mam.mff.cuni.cz'
# "Poslali jsme e-mail (pokud bylo kam))"
class PasswordResetDoneView(auth_views.PasswordResetDoneView): class PasswordResetDoneView(auth_views.PasswordResetDoneView):
""" Poslali jsme e-mail (pokud bylo kam)). """
#template_name = 'seminar/password_reset_done.html' #template_name = 'seminar/password_reset_done.html'
pass pass
# "Vymysli si heslo"
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView): class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
""" Vymysli si heslo. """
#template_name = 'seminar/password_confirm_done.html' #template_name = 'seminar/password_confirm_done.html'
success_url = reverse_lazy('reset_password_complete') success_url = reverse_lazy('reset_password_complete')
# "Heslo se asi změnilo."
class PasswordResetCompleteView(auth_views.PasswordResetCompleteView): class PasswordResetCompleteView(auth_views.PasswordResetCompleteView):
""" Heslo se asi změnilo."""
#template_name = 'seminar/password_complete_done.html' #template_name = 'seminar/password_complete_done.html'
pass pass

Loading…
Cancel
Save