diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index c724a07c..f7057aba 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -463,7 +463,8 @@ def body_resitelu(resitele, za, odjakziva=True): 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) )) + 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ě. body_k_zapocteni = Sum('reseni__hodnoceni__body', filter= Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte=rok)) @@ -503,10 +504,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True): ## 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) + aktivni_resitele = list(resi_v_rocniku(rocnik)) cisla = cisla_rocniku(rocnik, jen_verejne) body_cisla_slov = {} for cislo in cisla: @@ -636,10 +634,15 @@ def pricti_body(slovnik, resitel, body): slovnik[resitel.id] += body -def secti_body_za_rocnik(rocnik, aktivni_resitele): - """ Spočítá body za ročník, setřídí je sestupně a vrátí jako seznam.""" +def secti_body_za_rocnik(za, aktivni_resitele): + """ 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, rocnik, False) + resitel_rocnikbody_slov = body_resitelu(aktivni_resitele, za, False) # 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) @@ -685,6 +688,9 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None): # a mít více řešitelů for resitel in list(reseni.resitele.all()): + if resitel not in aktivni_resitele: + print("Skipping {}".format(resitel.id)) + continue pricti_body(cislobody, resitel, body) pricti_body(nadproblem_slovnik, resitel, body) return hlavni_problemy_slovnik, cislobody @@ -697,16 +703,13 @@ def vysledkovka_cisla(cislo, context=None): ## 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=cislo.rocnik.druhy_rok())) - # TODO: zkusit hodnoceni__rocnik... - #.filter(hodnoceni_set__rocnik__eq=cislo_rocnik) + aktivni_resitele = list(aktivniResitele(cislo.rocnik.rocnik, cislo.poradi)) # 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.rocnik, aktivni_resitele) + resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo, aktivni_resitele) # získáme body odjakživa resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo) @@ -808,58 +811,73 @@ class RocnikVysledkovkaView(RocnikView): #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani ### Generovani obalek +def resi_v_rocniku(rocnik, cislo=None): + """ Vrátí seznam řešitelů, co vyřešili nějaký problém v daném ročníku, do daného čísla. + Parametry: + rocnik (typu Rocnik) ročník, ze kterého chci řešitele, co něco odevzdali + cislo (typu Cislo) číslo, do kterého včetně se počítá, že v daném + ročníku řešitel něco poslal. + Pokud není zadané, počítají se všechna řešení z daného ročníku. + Výstup: + QuerySet objektů typu Resitel """ + + if cislo is None: + # filtrujeme pouze podle ročníku + letosni_reseni = Reseni.objects.filter(hodnoceni__cislo_body__rocnik = rocnik) + else: # filtrujeme podle ročníku i čísla + letosni_reseni = Reseni.objects.filter(hodnoceni__cislo_body__rocnik = rocnik, + hodnoceni__cislo_body__poradi__lte=cislo.poradi) + + # vygenerujeme queryset řešitelů, co letos něco poslali + letosni_resitele = Resitel.objects.none() + for reseni in letosni_reseni: + letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok()) + return letosni_resitele.distinct() + + +def aktivniResitele(rocnik, cislo): + """ Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali + a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). + Parametry: + rocnik (typu int) číslo ročníku, o který se jedná + cislo (typu int) pořadí čísla, o které se jedná -class CisloObalkyStruct: - rocnik = None - cisla = None - - -# Vraci QuerySet aktualnich resitelu = nekdy neco poslali, ale jeste neodmaturovali -def aktualniResitele(rocnik): + """ letos = Rocnik.objects.get(rocnik = rocnik) - return Resitel.objects.filter(rok_maturity__gt = letos.prvni_rok) -# # ALERT: pokud nekdo nema vypleny rok maturity, tak neni aktualni, protoze Karel Tesar a jini -# return Resitel.objects.filter(Q(rok_maturity__gt = letos.prvni_rok)|Q(rok_maturity = None)) - -# Vraci QuerySet aktivnich resitelu = -# jeste neodmaturovali && -# (pokud je aktualni cislo mensi nez 3, pak (letos || loni) neco poslali -# jinak letos neco poslali) -def aktivniResitele(rocnik,cislo): - letos = CisloObalkyStruct() - loni = CisloObalkyStruct() - - aktualni_resitele = aktualniResitele(rocnik) - - letos.rocnik = Rocnik.objects.get(rocnik = rocnik) - loni.rocnik = Rocnik.objects.get(rocnik = int(rocnik)-1) - letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik, cislo__lte = cislo) - loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik) - if int(cislo) > 3: - problemy = Problem.objects.filter(cislo_zadani__in = letos.cisla) - else: - problemy = Problem.objects.filter( - 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 + #TODO: co se stane, když zadané kombinace neexistují? ošetřit + aktualni_cislo = Cislo.objects.get(rocnik = rocnik, poradi = cislo) + loni = Rocnik.objects.get(rocnik = rocnik - 1) + # detekujeme, zda jde o první tři čísla či nikoli + zacatek_rocniku = True + try: + if int(aktualni_cislo.poradi) > 3: + zacatek_rocniku = False + except ValueError: + # pravděpodobně se jedná o číslo 7-8 + zacatek_rocniku = False + + if not zacatek_rocniku: + return resi_v_rocniku(letos) + else: + # spojíme querysety s řešiteli loni a letos do daného čísla + return (resi_v_rocniku(loni) | resi_v_rocniku(letos, aktualni_cislo)).distinct() -def cisloObalkyView(request,rocnik,cislo): - return obalkyView(request,aktivniResitele(rocnik,cislo)) +def cisloObalkyView(request, rocnik, cislo): + return obalkyView(request, aktivniResitele(rocnik, cislo)) -def obalkyView(request,resitele): +def obalkyView(request, resitele): tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content tempdir = tempfile.mkdtemp() with open(tempdir+"/obalky.tex","w") as texfile: - texfile.write(tex) - shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.pdf'),tempdir) - subprocess.call(["pdflatex","obalky.tex"],cwd = tempdir) + texfile.write(tex.decode()) + shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.pdf'), tempdir) + subprocess.call(["pdflatex","obalky.tex"], cwd = tempdir) with open(tempdir+"/obalky.pdf","rb") as pdffile: - response = HttpResponse(pdffile.read(),content_type='application/pdf') + response = HttpResponse(pdffile.read(), content_type='application/pdf') shutil.rmtree(tempdir) return response