From 3b328e4b00fee2ea7525d21ccce6d4e578d12d39 Mon Sep 17 00:00:00 2001 From: Anet Date: Wed, 25 Mar 2020 23:57:11 +0100 Subject: [PATCH] =?UTF-8?q?V=C3=BDsledkovka=20=C4=8D=C3=ADsla=20p=C5=99esu?= =?UTF-8?q?nuta=20do=20funkce=20a=20rozsek=C3=A1na=20na=20men=C5=A1=C3=AD?= =?UTF-8?q?=20kusy,=20optimalizace=20k=C3=B3du.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/views_all.py | 312 ++++++++++++++++++------------------- 1 file changed, 152 insertions(+), 160 deletions(-) diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 71bad834..97747523 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -61,7 +61,7 @@ class VlozBodyView(generic.ListView): print(self.tema) self.problemy = Problem.objects.filter(nadproblem = self.tema) print(self.problemy) - self.reseni = Reseni.objects.filter(problem__in=self.problemy) + self.reseni = Reseni.objects.filter(problem__in=self.problemy) print(self.reseni) return self.reseni @@ -80,7 +80,7 @@ class ObalkovaniView(generic.ListView): def get_context_data(self, **kwargs): context = super(ObalkovaniView, self).get_context_data(**kwargs) print(self.cislo) - context['cislo'] = self.cislo + context['cislo'] = self.cislo return context class TNLData(object): @@ -106,18 +106,22 @@ class TreeNodeView(generic.DetailView): return context -class AktualniZadaniView(TreeNodeView): - def get_object(self): - nastaveni = get_object_or_404(Nastaveni) - return nastaveni.aktualni_cislo.cislonode - - def get_context_data(self,**kwargs): - nastaveni = get_object_or_404(Nastaveni) - context = super().get_context_data(**kwargs) - verejne = nastaveni.aktualni_cislo.verejne() - context['verejne'] = verejne - return context +#def AktualniZadaniView(request): +# nastaveni = get_object_or_404(Nastaveni) +# verejne = nastaveni.aktualni_cislo.verejne() +# problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') +# ulohy = problemy.filter(typ = 'uloha').order_by('kod') +# serialy = problemy.filter(typ = 'serial').order_by('kod') +# jednorazove_problemy = [ulohy, serialy] +# return render(request, 'seminar/zadani/AktualniZadani.html', +# {'nastaveni': nastaveni, +# 'jednorazove_problemy': jednorazove_problemy, +# 'temata': verejna_temata(nastaveni.aktualni_rocnik), +# 'verejne': verejne, +# }, +# ) +# #def ZadaniTemataView(request): # nastaveni = get_object_or_404(Nastaveni) # temata = verejna_temata(nastaveni.aktualni_rocnik) @@ -285,6 +289,7 @@ class CojemamOrganizatoriStariView(generic.ListView): ### Archiv + class ArchivView(generic.ListView): model = Rocnik template_name='seminar/archiv/cisla.html' @@ -295,16 +300,13 @@ class ArchivView(generic.ListView): vyska = 297 # px sirka = 210 # px - # nejnovějších 10 zveřejněných čísel cisla = Cislo.objects.filter(verejne_db=True)[:10] - # op = os.path, udělá z argumentů cestu png_dir = op.join(settings.MEDIA_ROOT, "cislo", "png") # seznam [(url obrázku, číslo)] urls = [] - # c je číslo, i je pořadí čísla for i, c in enumerate(cisla): if not c.pdf: continue @@ -396,7 +398,7 @@ def sloupec_s_poradim(seznam_s_body): sloupec_s_poradim.append("{}.".format(aktualni_poradi)) # pokud je skupina větší, vypíšu rozsah else: - sloupec_s_poradim.append("{}.–{}.".format(aktualni_poradi, + sloupec_s_poradim.append("{}.–{}.".format(aktualni_poradi, aktualni_poradi+velikost_skupiny-1)) # zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno aktualni_poradi = aktualni_poradi + velikost_skupiny @@ -404,10 +406,10 @@ def sloupec_s_poradim(seznam_s_body): ## 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 +# # 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, +# 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 @@ -415,7 +417,7 @@ def sloupec_s_poradim(seznam_s_body): # soucet += r.body # # # a přičteme k tomu hodnocení všech podproblémů -# for p in problem.podproblem.all(): +# 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 @@ -433,14 +435,15 @@ def hlavni_problem(problem): # 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() # hodnocení, která se vážou k danému číslu - + hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all() + # hodnocení, která se vážou k danému číslu + reseni = [h.reseni for h in hodnoceni] problemy = [h.problem for h in hodnoceni] problemy_set = set(problemy) # chceme každý problém unikátně, problemy = (list(problemy_set)) # převedení na množinu a zpět to zaručí - # hlavní problémy čísla + # hlavní problémy čísla # (mají vlastní sloupeček ve výsledkovce, nemají nadproblém) hlavni_problemy = [] for p in problemy: @@ -450,16 +453,16 @@ def hlavni_problemy_cisla(cislo): 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 t1, t2, c3, ... - + return hlavni_problemy # vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník -# POZOR! Aktuálně počítá jen za posledních 10 let od zadaného ročníku def body_resitelu_odjakziva(rocnik, resitele): body_odjakziva = {} 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) # @@ -497,38 +500,6 @@ def body_resitelu_za_rocnik(rocnik, aktivni_resitele): pricti_body(body_za_rocnik, resitel, hodn.body) return body_za_rocnik -#def body_resitele_odjakziva(resitel): -# body = 0 -# resitelova_hodnoceni = Hodnoceni.objects.select_related('body').all().filter(reseni_resitele=resitel) -# # TODO: v radku nahore chceme _in nebo _contains -# for hodnoceni in resitelova_hodnoceni: -# body = body + hodnoceni.body -# return body - -# spočítá součet všech bodů řešitele za dané číslo -#def body_resitele_v_cisle(resitel, cislo): -# hlavni_problemy = hlavni_problemy_cisla(cislo) -# body_resitele = 0 -# for h in hlavni_problemy: -# body_resitele = body_resitele + body_resitele_problemu_v_cisle(h, resitel, cislo) -# # TODO: je rozdíl mezi odevzdanou úlohou za 0 a tím, když řešitel nic neodevzdal -# # řešit přes kontrolu velikosti množiny řešení daného problému do daného čísla? -# # Tady to ale nevadí, tady se počítá součet za číslo. -# return body_resitele - -# spočítá součet všech bodů řešitele za daný rok (nebo jen do daného čísla včetně) -#def body_resitele_v_rocniku(resitel, rocnik, do_cisla=None): -# # pokud do_cisla=None, tak do posledního čísla v ročníku -# # do_cisla je objekt Cislo -# cisla = rocnik.cisla.all() # funkce vrátí pole objektů -# # Cislo už lexikograficky setřízené, viz models -# body = 0 -# for cislo in cisla: -# if cislo.poradi == do_cisla.poradi: break -# # druhá část zaručuje, že máme výsledky do daného čísla včetně -# body = body + body_resitele_v_cisle(resitel, cislo) -# return body - # 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 @@ -662,6 +633,120 @@ def pricti_body(slovnik, resitel, body): slovnik[str(resitel.id)] += body +def secti_body_za_rocnik(cislo, 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) + # 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): + # 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ů) + hlavni_problemy_slovnik = {} + for hp in hlavni_problemy: + hlavni_problemy_slovnik[str(hp.id)] = {} + + # zakládání prázdných záznamů pro řešitele + cislobody = {} + for ar in aktivni_resitele: + # řešitele převedeme na řetězec pomocí unikátního id + cislobody[str(ar.id)] = "" + for hp in hlavni_problemy: + slovnik = hlavni_problemy_slovnik[str(hp.id)] + slovnik[str(ar.id)] = "" + + # vezmeme všechna řešení s body do daného čísla + reseni_do_cisla = Reseni.objects.prefetch_related('problem', 'resitele', + 'hodnoceni_set').filter(hodnoceni__cislo_body=cislo) + + # projdeme všechna řešení do čísla a přičteme body každému řešiteli do celkových + # bodů i do bodů za problém + for reseni in reseni_do_cisla: + + # řešení může řešit více problémů + for prob in list(reseni.problem.all()): + nadproblem = hlavni_problem(prob) + nadproblem_slovnik = hlavni_problemy_slovnik[str(nadproblem.id)] + + # a mít více hodnocení + for hodn in list(reseni.hodnoceni_set.all()): + body = hodn.body + + # a mít více řešitelů + for resitel in list(reseni.resitele.all()): + pricti_body(cislobody, resitel, body) + pricti_body(nadproblem_slovnik, resitel, body) + return hlavni_problemy_slovnik, cislobody + + +def spocti_vysledkovku_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 + aktivni_resitele = list(Resitel.objects.filter( + rok_maturity__gte=cislo.rocnik.druhy_rok())) + # TODO: zkusit hodnoceni__rocnik... + #.filter(hodnoceni_set__rocnik__eq=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) + + # získáme body odjakživa + resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik.druhy_rok(), + aktivni_resitele) + + # řešitelé setřídění podle bodů za číslo sestupně + setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] + setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id] + + # 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) + + # vytvoříme jednotlivé sloupce výsledkovky + radky_vysledkovky = [] + i = 0 + for ar_id in setrizeni_resitele_id: + # získáme seznam bodů za problémy pro daného řešitele + problemy = [] + 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( + poradi[i], # pořadí + Resitel.objects.get(id=ar_id), # řešitel (z id) + problemy, # seznam bodů za hlavní problémy čísla + cislobody[ar_id], # body za číslo + 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 + 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) + print("Přikládám {}-tý řádek.".format(i)) + i += 1 + + print("Následuje předávání do kontextu.") + # vytahané informace předáváme do kontextu + context['cislo'] = cislo + context['radky_vysledkovky'] = radky_vysledkovky + context['problemy'] = hlavni_problemy + #context['v_cisle_zadane'] = TODO + #context['resene_problemy'] = resene_problemy + print("Předávám kontext.") + return context + class CisloView(generic.DetailView): model = Cislo template_name = 'seminar/archiv/cislo.html' @@ -685,101 +770,8 @@ class CisloView(generic.DetailView): context = super(CisloView, self).get_context_data(**kwargs) cislo = context['cislo'] - hlavni_problemy = hlavni_problemy_cisla(cislo) - # 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ů) - hlavni_problemy_slovnik = {} - for hp in hlavni_problemy: - hlavni_problemy_slovnik[str(hp.id)] = {} - - ## 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 - aktivni_resitele = list(Resitel.objects.filter( - rok_maturity__gte=cislo.rocnik.druhy_rok())) - # TODO: zkusit hodnoceni__rocnik... - #.filter(hodnoceni_set__rocnik__eq=cislo_rocnik) - # zakládání prázdných záznamů pro řešitele - cislobody = {} - for ar in aktivni_resitele: - # řešitele převedeme na řetězec pomocí unikátního id - cislobody[str(ar.id)] = "" - for hp in hlavni_problemy: - slovnik = hlavni_problemy_slovnik[str(hp.id)] - slovnik[str(ar.id)] = "" - - # vezmeme všechna řešení s body do daného čísla - reseni_do_cisla = Reseni.objects.prefetch_related('problem', 'resitele', 'hodnoceni_set').filter(hodnoceni__cislo_body=cislo) - - # projdeme všechna řešení do čísla a přičteme body každému řešiteli do celkových - # bodů i do bodů za problém - for reseni in reseni_do_cisla: - - # řešení může řešit více problémů - for prob in list(reseni.problem.all()): - nadproblem = hlavni_problem(prob) - nadproblem_slovnik = hlavni_problemy_slovnik[str(nadproblem.id)] - - # a více hodnocení - for hodn in list(reseni.hodnoceni_set.all()): - body = hodn.body - - # a více řešitelů - for resitel in list(reseni.resitele.all()): - pricti_body(cislobody, resitel, body) - pricti_body(nadproblem_slovnik, resitel, body) - - # zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně - resitel_rocnikbody_slov = body_resitelu_za_rocnik(cislo.rocnik, aktivni_resitele) - resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(), - key = lambda x: x[1], reverse = True) - - # získáme body odjakživa - resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik.druhy_rok(), - aktivni_resitele) - - # řešitelé setřídění podle bodů za číslo sestupně - setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] - setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id] - - # vytvoříme jednotlivé sloupce výsledkovky - radky_vysledkovky = [] - odjakziva_body = [] - rocnik_body = [] - cislo_body = [] - hlavni_problemy_body = [] - for ar_id in setrizeni_resitele_id: - # vytáhneme ze slovníků body pro daného řešitele - odjakziva_body.append(resitel_odjakzivabody_slov[ar_id]) - rocnik_body.append(resitel_rocnikbody_slov[ar_id]) - cislo_body.append(cislobody[ar_id]) - problemy = [] - for hp in hlavni_problemy: - problemy.append(hlavni_problemy_slovnik[str(hp.id)][ar_id]) - hlavni_problemy_body.append(problemy) - print("{}: body za problémy - {}, číslobody - {}, ročníkbody - {}, odjakživabody - ".format(ar_id, problemy, cislobody[ar_id], resitel_rocnikbody_slov[ar_id])) - # pořadí určíme pomocí funkce, které dáme celkové body za ročník vzestupně - poradi = sloupec_s_poradim(rocnik_body) - - radky_vysledkovky = [] - for i in range(0, len(setrizeni_resitele_id)): - radek = RadekVysledkovky(poradi[i], setrizeni_resitele[i], - hlavni_problemy_body[i], cislo_body[i], rocnik_body[i], - odjakziva_body[i]) - radky_vysledkovky.append(radek) - print("Přikládám {}-tý řádek.".format(i)) - - print("Následuje předávání do kontextu.") - # vytahané informace předáváme do kontextu - context['cislo'] = cislo - context['radky_vysledkovky'] = radky_vysledkovky - context['problemy'] = hlavni_problemy -# context['v_cisle_zadane'] = TODO -# context['resene_problemy'] = resene_problemy - print("Předávám kontext.") - return context + # vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky + return spocti_vysledkovku_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 @@ -1006,7 +998,7 @@ def soustredeniUcastniciExportView(request,soustredeni): class ClankyResitelView(generic.ListView): model = Problem template_name = 'seminar/clanky/resitelske_clanky.html' - queryset = Clanek.objects.filter(stav=Problem.STAV_ZADANY, resitelsky=True).select_related('cislo__rocnik').order_by('-cislo__rocnik__rocnik', 'kod') + queryset = Clanek.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') # FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit #class ClankyOrganizatorView(generic.ListView): @@ -1292,7 +1284,7 @@ def loginView(request): if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): - user = authenticate(request, + user = authenticate(request, username=form.cleaned_data['username'], password=form.cleaned_data['password']) print(form.cleaned_data) @@ -1300,8 +1292,8 @@ def loginView(request): login(request,user) return HttpResponseRedirect('/') else: - return render(request, - 'seminar/login.html', + return render(request, + 'seminar/login.html', {'form': form, 'login_error': 'Neplatné jméno nebo heslo'}) else: @@ -1319,7 +1311,7 @@ def logoutView(request): def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data): msg = "{}, form_hash:{}".format(msg,hash(form_data)) logger.warn(msg) - gdpr_logger.warn(msg+", form:{}".format(form_data)) + gdpr_logger.warn(msg+", form:{}".format(form_data)) from django.forms.models import model_to_dict def resitelEditView(request): @@ -1329,7 +1321,7 @@ def resitelEditView(request): osoba_edit = Osoba.objects.get(user=u) resitel_edit = osoba_edit.resitel user_edit = osoba_edit.user - ## Vytvoření slovníku, kterým předvyplním formulář + ## Vytvoření slovníku, kterým předvyplním formulář prefill_1=model_to_dict(user_edit) prefill_2=model_to_dict(resitel_edit) prefill_3=model_to_dict(osoba_edit) @@ -1387,7 +1379,7 @@ def prihlaskaView(request): fcd = form.cleaned_data form_hash = hash(fcd) form_logger.info(fcd,form_hash=form_hash) - + with transaction.atomic(): u = User.objects.create_user( username=fcd['username'], @@ -1426,7 +1418,7 @@ def prihlaskaView(request): rok_maturity = fcd['rok_maturity'], zasilat = fcd['zasilat'] ) - + r.save() r.osoba = o if fcd.get('skola'):