Přepsání výsledkovek v1
This commit is contained in:
parent
79d9636c28
commit
ba7e3409a2
14 changed files with 490 additions and 546 deletions
|
@ -40,7 +40,7 @@ class OrgoRozcestnikView(TemplateView):
|
||||||
# přes treenody (a dát si přitom pozor na MezicisloNode)
|
# přes treenody (a dát si přitom pozor na MezicisloNode)
|
||||||
|
|
||||||
neobodovana_reseni = s.Hodnoceni.objects.filter(body__isnull=True)
|
neobodovana_reseni = s.Hodnoceni.objects.filter(body__isnull=True)
|
||||||
reseni_mimo_cislo = s.Hodnoceni.objects.filter(cislo_body__isnull=True)
|
reseni_mimo_cislo = s.Hodnoceni.objects.filter(deadline_body__isnull=True)
|
||||||
context['pocet_neobodovanych_reseni'] = neobodovana_reseni.count()
|
context['pocet_neobodovanych_reseni'] = neobodovana_reseni.count()
|
||||||
context['pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.count()
|
context['pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.count()
|
||||||
|
|
||||||
|
|
|
@ -323,7 +323,7 @@ class Resitel(SeminarModelBase):
|
||||||
# - proto se započítávají dvojnásobně a byly posunuté hranice titulů
|
# - proto se započítávají dvojnásobně a byly posunuté hranice titulů
|
||||||
# - staré tituly se ale nemají odebrat, pokud řešitel v t.č. minulém (26.) ročníku měl titul, má ho mít pořád.
|
# - staré tituly se ale nemají odebrat, pokud řešitel v t.č. minulém (26.) ročníku měl titul, má ho mít pořád.
|
||||||
from .odevzdavatko import Hodnoceni
|
from .odevzdavatko import Hodnoceni
|
||||||
hodnoceni_do_25_rocniku = Hodnoceni.objects.filter(cislo_body__rocnik__rocnik__lte=25,reseni__in=self.reseni_set.all())
|
hodnoceni_do_25_rocniku = Hodnoceni.objects.filter(deadline_body__cislo__rocnik__rocnik__lte=25,reseni__in=self.reseni_set.all())
|
||||||
novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku)
|
novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku)
|
||||||
|
|
||||||
def body_z_hodnoceni(hh : list):
|
def body_z_hodnoceni(hh : list):
|
||||||
|
@ -361,7 +361,7 @@ class Resitel(SeminarModelBase):
|
||||||
return Titul.akad
|
return Titul.akad
|
||||||
|
|
||||||
from .odevzdavatko import Hodnoceni
|
from .odevzdavatko import Hodnoceni
|
||||||
hodnoceni_do_26_rocniku = Hodnoceni.objects.filter(cislo_body__rocnik__rocnik__lte=26,reseni__in=self.reseni_set.all())
|
hodnoceni_do_26_rocniku = Hodnoceni.objects.filter(deadline_body__cislo__rocnik__rocnik__lte=26,reseni__in=self.reseni_set.all())
|
||||||
novejsi_body = body_z_hodnoceni(
|
novejsi_body = body_z_hodnoceni(
|
||||||
Hodnoceni.objects.filter(reseni__in=self.reseni_set.all())
|
Hodnoceni.objects.filter(reseni__in=self.reseni_set.all())
|
||||||
.difference(hodnoceni_do_26_rocniku)
|
.difference(hodnoceni_do_26_rocniku)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import logging
|
||||||
|
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
@ -328,6 +329,9 @@ class Cislo(SeminarModelBase):
|
||||||
if self.datum_deadline_soustredeni is not None and self.datum_deadline_soustredeni > self.datum_deadline:
|
if self.datum_deadline_soustredeni is not None and self.datum_deadline_soustredeni > self.datum_deadline:
|
||||||
raise ValidationError({'datum_deadline_soustredeni': "Soustřeďkový deadline musí předcházet finálnímu deadlinu"})
|
raise ValidationError({'datum_deadline_soustredeni': "Soustřeďkový deadline musí předcházet finálnímu deadlinu"})
|
||||||
|
|
||||||
|
def zlomovy_deadline_pro_papirove_cislo(self):
|
||||||
|
return Deadline.objects.filter(Q(typ=Deadline.TYP_PRVNI) | Q(typ=Deadline.TYP_PRVNI_A_SOUS), cislo=self).first()
|
||||||
|
|
||||||
|
|
||||||
class Deadline(SeminarModelBase):
|
class Deadline(SeminarModelBase):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -365,6 +369,12 @@ class Deadline(SeminarModelBase):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.CHOICES_MAP[self.typ] + " " + str(self.cislo)
|
return self.CHOICES_MAP[self.typ] + " " + str(self.cislo)
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return Deadline.objects.filter(gt=self).first()
|
||||||
|
|
||||||
|
def previous(self):
|
||||||
|
return Deadline.objects.filter(lt=self).last()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(ignore_duplicates=True)
|
@reversion.register(ignore_duplicates=True)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
\setlength{\tabcolsep}{3pt}
|
\setlength{\tabcolsep}{3pt}
|
||||||
\begin{longtable}{|r|l|c|r|{% for p in problemy %}c@{\hskip.5em}{% endfor %}|r|r|}\hline
|
\begin{longtable}{|r|l|c|r|{% for p in vysledkovka.temata_a_spol %}c@{\hskip.5em}{% endfor %}|r|r|}\hline
|
||||||
& & & & \multicolumn{ {{ problemy|length}} }{c|}{\textbf{Témata}} & & \\\textbf{Poř.}& \textbf{Jméno}& \textbf{R.}& \raisebox{0.7mm}{$\sum_{-1}$}& {% for p in problemy %}\textbf{ {{ p.kod_v_rocniku }} }&{% endfor %}\raisebox{0.7mm}{$\sum_0$}&\raisebox{0.7mm}{$\sum_1$}\\\hline
|
& & & & \multicolumn{ {{ vysledkovka.temata_a_spol|length}} }{c|}{\textbf{Témata}} & & \\\textbf{Poř.}& \textbf{Jméno}& \textbf{R.}& \raisebox{0.7mm}{$\sum_{-1}$}& {% for p in vysledkovka.temata_a_spol %}\textbf{ {{ p.kod_v_rocniku }} }&{% endfor %}\raisebox{0.7mm}{$\sum_0$}&\raisebox{0.7mm}{$\sum_1$}\\\hline
|
||||||
\endhead
|
\endhead
|
||||||
\hline
|
\hline
|
||||||
\endfoot
|
\endfoot
|
||||||
{% for rv in radky_vysledkovky %}{{rv.poradi}}&{% if rv.titul %}\titul{ {{ rv.titul}}}{% endif %}{{rv.resitel.osoba.jmeno|slice:":1"}}. {{rv.resitel.osoba.prijmeni}}&{{rv.rocnik_resitele|default:""}}&{{rv.body_celkem_odjakziva}}&{% for b in rv.body_problemy_sezn %}{{b}}&{% endfor %}{{rv.body_cislo}}&{{rv.body_rocnik|default:0}}\\
|
{% for rv in vysledkovka.radky_vysledkovky %}{{rv.poradi}}&{% if rv.titul %}\titul{ {{ rv.titul}}}{% endif %}{{rv.resitel.osoba.jmeno|slice:":1"}}. {{rv.resitel.osoba.prijmeni}}&{{rv.rocnik_resitele|default:""}}&{{rv.body_celkem_odjakziva}}&{% for b in rv.body_problemy_sezn %}{{b}}&{% endfor %}{{rv.body_cislo}}&{{rv.body_rocnik|default:0}}\\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
\end{longtable}
|
\end{longtable}
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% if vysledkovka %}
|
{% if vysledkovka.radky_vysledkovky %}
|
||||||
<h2>Výsledková listina</h2>
|
<h2>Výsledková listina</h2>
|
||||||
{% include "vysledkovky/vysledkovka_rocnik.html" %}
|
{% include "vysledkovky/vysledkovka_rocnik.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
{# FIXME: Sice to sem asi nepatří sémanticky, ale bylo to nejjednodušší… #}
|
{# FIXME: Sice to sem asi nepatří sémanticky, ale bylo to nejjednodušší… #}
|
||||||
<p><a href='{% url 'seminar_rocnik_resitele_csv' rocnik=rocnik.rocnik %}' download>CSV export řešitelů</a></p>
|
<p><a href='{% url 'seminar_rocnik_resitele_csv' rocnik=rocnik.rocnik %}' download>CSV export řešitelů</a></p>
|
||||||
<h2>Výsledková listina včetně neveřejných bodů</h2>
|
<h2>Výsledková listina včetně neveřejných bodů</h2>
|
||||||
{% include "vysledkovky/vysledkovka_rocnik_neverejna.html" %}
|
{% include "vysledkovky/vysledkovka_rocnik.html" with vysledkovka=vysledkovka_neverejna %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
{% with lb="{" %}
|
{% with lb="{" %}
|
||||||
{% with rb="}" %}
|
{% with rb="}" %}
|
||||||
{% with radky_vysledkovky=radky_vysledkovky_s_neverejnymi cisla=cisla_s_neverejnymi %}
|
{% with vysledkovka=vysledkovka_neverejna %}
|
||||||
\setlength{\tabcolsep}{3pt}
|
\setlength{\tabcolsep}{3pt}
|
||||||
\begin{longtable}{|r|l|c|r|{% for cislo in cisla %}c{% if not forloop.last %}@{\hskip.5em}{% endif %}{% endfor %}|r|}\hline
|
\begin{longtable}{|r|l|c|r|{% for cislo in vysledkovka.cisla_rocniku %}c{% if not forloop.last %}@{\hskip.5em}{% endif %}{% endfor %}|r|}\hline
|
||||||
& & & & \multicolumn{{ lb }}{{ cisla|length }}}{c|}{\textbf{Číslo}} & \\\textbf{Poř.} & \textbf{Jméno} & \textbf{R.} & \raisebox{0.7mm}{$\sum_{-1}$} & {% for cislo in cisla %}\textbf{{ lb }}{{ cislo.poradi }}{{ rb }} & {% endfor %}\raisebox{0.7mm}{$\sum_1$} \\\hline
|
& & & & \multicolumn{{ lb }}{{ vysledkovka.cisla_rocniku|length }}}{c|}{\textbf{Číslo}} & \\\textbf{Poř.} & \textbf{Jméno} & \textbf{R.} & \raisebox{0.7mm}{$\sum_{-1}$} & {% for cislo in vysledkovka.cisla_rocniku %}\textbf{{ lb }}{{ cislo.poradi }}{{ rb }} & {% endfor %}\raisebox{0.7mm}{$\sum_1$} \\\hline
|
||||||
\endhead
|
\endhead
|
||||||
\hline
|
\hline
|
||||||
\endfoot
|
\endfoot
|
||||||
{% for rv in radky_vysledkovky %}{{ rv.poradi }} & {% if rv.titul %}\titul{{ lb }}{{ rv.titul }}}~{% endif %}{{ rv.resitel.osoba.jmeno|slice:":1" }}.~{{ rv.resitel.osoba.prijmeni }} & {% if rv.rocnik_resitele %}{{ rv.rocnik_resitele }}{% endif %} & {{ rv.body_celkem_odjakziva }} {% for b in rv.body_cisla_sezn %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\
|
{% for rv in vysledkovka.radky_vysledkovky %}{{ rv.poradi }} & {% if rv.titul %}\titul{{ lb }}{{ rv.titul }}}~{% endif %}{{ rv.resitel.osoba.jmeno|slice:":1" }}.~{{ rv.resitel.osoba.prijmeni }} & {% if rv.rocnik_resitele %}{{ rv.rocnik_resitele }}{% endif %} & {{ rv.body_celkem_odjakziva }} {% for b in rv.body_cisla_sezn %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\
|
||||||
{% endfor %}\end{longtable}
|
{% endfor %}\end{longtable}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
{% if radky_vysledkovky %}
|
{% if vysledkovka.radky_vysledkovky %}
|
||||||
{% include "vysledkovky/vysledkovka_rocnik.html" %}
|
{% include "vysledkovky/vysledkovka_rocnik.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>V tomto ročníku zatím žádné výsledky nejsou.</p>
|
<p>V tomto ročníku zatím žádné výsledky nejsou.</p>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
{% if user.je_org and vysledkovka_s_neverejnymi %}
|
{% if user.je_org and vysledkovka_s_neverejnymi %}
|
||||||
<div class='mam-org-only'>
|
<div class='mam-org-only'>
|
||||||
<h1>Výsledky včetně neveřejných</h1>
|
<h1>Výsledky včetně neveřejných</h1>
|
||||||
{% include "vysledkovky/vysledkovka_rocnik_neverejna.html" %}
|
{% include "vysledkovky/vysledkovka_rocnik.html" with vysledkovka=vysledkovka_neverejna %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -179,11 +179,11 @@ def resi_v_rocniku(rocnik, cislo=None):
|
||||||
if cislo is None:
|
if cislo is None:
|
||||||
# filtrujeme pouze podle ročníku
|
# filtrujeme pouze podle ročníku
|
||||||
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
||||||
reseni__hodnoceni__cislo_body__rocnik=rocnik).distinct()
|
reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik).distinct()
|
||||||
else: # filtrujeme podle ročníku i čísla
|
else: # filtrujeme podle ročníku i čísla
|
||||||
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
||||||
reseni__hodnoceni__cislo_body__rocnik=rocnik,
|
reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik,
|
||||||
reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi).distinct()
|
reseni__hodnoceni__deadline_body__cislo__poradi__lte=cislo.poradi).distinct()
|
||||||
|
|
||||||
|
|
||||||
def aktivniResitele(cislo, pouze_letosni=False):
|
def aktivniResitele(cislo, pouze_letosni=False):
|
||||||
|
@ -269,11 +269,11 @@ def hlavni_problem(problem):
|
||||||
return problem
|
return problem
|
||||||
|
|
||||||
def problemy_rocniku(rocnik, jen_verejne=True):
|
def problemy_rocniku(rocnik, jen_verejne=True):
|
||||||
return m.Problem.objects.filter(hodnoceni__in = m.Hodnoceni.objects.filter(cislo_body__in = cisla_rocniku(rocnik, jen_verejne))).distinct().select_related('nadproblem').select_related('nadproblem__nadproblem')
|
return m.Problem.objects.filter(hodnoceni__in = m.Hodnoceni.objects.filter(deadline_body__cislo__in = cisla_rocniku(rocnik, jen_verejne))).distinct().select_related('nadproblem').select_related('nadproblem__nadproblem')
|
||||||
|
|
||||||
def problemy_cisla(cislo):
|
def problemy_cisla(cislo):
|
||||||
""" Vrátí seznam všech problémů s body v daném čísle. """
|
""" Vrátí seznam všech problémů s body v daném čísle. """
|
||||||
return m.Problem.objects.filter(hodnoceni__in = m.Hodnoceni.objects.filter(cislo_body = cislo)).distinct().non_polymorphic().select_related('nadproblem').select_related('nadproblem__nadproblem')
|
return m.Problem.objects.filter(hodnoceni__in = m.Hodnoceni.objects.filter(deadline_body__cislo = cislo)).distinct().non_polymorphic().select_related('nadproblem').select_related('nadproblem__nadproblem')
|
||||||
|
|
||||||
|
|
||||||
def hlavni_problemy_f(problemy=None):
|
def hlavni_problemy_f(problemy=None):
|
||||||
|
|
|
@ -17,8 +17,8 @@ from seminar import utils
|
||||||
from treenode import treelib
|
from treenode import treelib
|
||||||
import treenode.templatetags as tnltt
|
import treenode.templatetags as tnltt
|
||||||
import treenode.serializers as vr
|
import treenode.serializers as vr
|
||||||
from vysledkovky.utils import body_resitelu
|
from vysledkovky.utils import body_resitelu, VysledkovkaCisla, \
|
||||||
from vysledkovky.views import vysledkovka_rocniku, vysledkovka_cisla
|
VysledkovkaRocniku
|
||||||
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -206,26 +206,17 @@ def ZadaniAktualniVysledkovkaView(request):
|
||||||
nastaveni = get_object_or_404(Nastaveni)
|
nastaveni = get_object_or_404(Nastaveni)
|
||||||
# Aktualni verejna vysledkovka
|
# Aktualni verejna vysledkovka
|
||||||
rocnik = nastaveni.aktualni_rocnik
|
rocnik = nastaveni.aktualni_rocnik
|
||||||
context = vysledkovka_rocniku(
|
context = {'vysledkovka': VysledkovkaRocniku(rocnik, True)}
|
||||||
rocnik=rocnik,
|
|
||||||
request=request,
|
|
||||||
sneverejnou=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# kdyz neni verejna vysledkovka, tak zobraz starou
|
# kdyz neni verejna vysledkovka, tak zobraz starou
|
||||||
if len(context['cisla']) == 0:
|
if len(context['vysledkovka'].cisla_rocniku) == 0:
|
||||||
try:
|
try:
|
||||||
minuly_rocnik = Rocnik.objects.get(
|
minuly_rocnik = Rocnik.objects.get(
|
||||||
prvni_rok=(rocnik.prvni_rok-1))
|
rocnik=(rocnik.rocnik-1))
|
||||||
rocnik = minuly_rocnik
|
rocnik = minuly_rocnik
|
||||||
|
|
||||||
# Přepíšeme prázdnou výsledkovku výsledkovkou z minulého ročníku
|
# Přepíšeme prázdnou výsledkovku výsledkovkou z minulého ročníku
|
||||||
context = vysledkovka_rocniku(
|
context['vysledkovka'] = VysledkovkaRocniku(rocnik, True)
|
||||||
rocnik=rocnik,
|
|
||||||
context=context,
|
|
||||||
request=request,
|
|
||||||
sneverejnou=True
|
|
||||||
)
|
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -377,17 +368,10 @@ class RocnikView(generic.DetailView):
|
||||||
return get_object_or_404(queryset,rocnik=self.kwargs.get('rocnik'))
|
return get_object_or_404(queryset,rocnik=self.kwargs.get('rocnik'))
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
start = time.time()
|
|
||||||
context = super(RocnikView, self).get_context_data(**kwargs)
|
context = super(RocnikView, self).get_context_data(**kwargs)
|
||||||
context = vysledkovka_rocniku(
|
context["vysledkovka"] = VysledkovkaRocniku(context["rocnik"], True)
|
||||||
rocnik=context["rocnik"],
|
context["neprazdna_vysledkovka"] = len(context['vysledkovka'].cisla_rocniku) != 0
|
||||||
context=context,
|
context["vysledkovka_neverejna"] = VysledkovkaRocniku(context["rocnik"], False)
|
||||||
request=self.request,
|
|
||||||
sneverejnou=True
|
|
||||||
)
|
|
||||||
end = time.time()
|
|
||||||
print("Kontext:", end-start)
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def resiteleRocnikuCsvExportView(request, rocnik):
|
def resiteleRocnikuCsvExportView(request, rocnik):
|
||||||
|
@ -453,7 +437,8 @@ class CisloView(generic.DetailView):
|
||||||
cislo = context['cislo']
|
cislo = context['cislo']
|
||||||
context['prevcislo'] = Cislo.objects.filter((Q(rocnik__lt=self.object.rocnik) | Q(poradi__lt=self.object.poradi))&Q(rocnik__lte=self.object.rocnik)).first()
|
context['prevcislo'] = Cislo.objects.filter((Q(rocnik__lt=self.object.rocnik) | Q(poradi__lt=self.object.poradi))&Q(rocnik__lte=self.object.rocnik)).first()
|
||||||
# vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky
|
# vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky
|
||||||
return vysledkovka_cisla(cislo, context)
|
context['vysledkovka'] = VysledkovkaCisla(cislo, not self.request.user.je_org)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ArchivTemataView(generic.ListView):
|
class ArchivTemataView(generic.ListView):
|
||||||
|
|
|
@ -3,21 +3,21 @@
|
||||||
<tr class='border-b'>
|
<tr class='border-b'>
|
||||||
<th class='border-r'>#
|
<th class='border-r'>#
|
||||||
<th class='border-r'>Jméno
|
<th class='border-r'>Jméno
|
||||||
{% for p in problemy %}
|
{% for p in vysledkovka.temata_a_spol%}
|
||||||
<th class='border-r' id="problem{{ forloop.counter0 }}">{# <a href="{{ p.verejne_url }}"> #}{{ p.kod_v_rocniku }}{# </a> #}
|
<th class='border-r' id="problem{{ forloop.counter0 }}">{# <a href="{{ p.verejne_url }}"> #}{{ p.kod_v_rocniku }}{# </a> #}
|
||||||
|
|
||||||
{# TODELETE #}
|
{# TODELETE #}
|
||||||
{% for podproblemy in podproblemy_iter.next %}
|
{% for podproblemy in vysledkovka.podproblemy_iter.next %}
|
||||||
<th class='border-r podproblem{{ forloop.parentloop.counter0 }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}
|
<th class='border-r podproblem{{ forloop.parentloop.counter0 }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{# TODELETE #}
|
{# TODELETE #}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if ostatni %}<th class='border-r' id='problem{{ problemy | length }}'>Ostatní {% endif %}
|
{% if vysledkovka.ostatni %}<th class='border-r' id='problem{{ vysledkovka.temata_a_spol| length }}'>Ostatní {% endif %}
|
||||||
|
|
||||||
{# TODELETE #}
|
{# TODELETE #}
|
||||||
{% for podproblemy in podproblemy_iter.next %}
|
{% for podproblemy in podproblemy_iter.next %}
|
||||||
<th class='border-r podproblem{{ problemy | length }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}
|
<th class='border-r podproblem{{ vysledkovka.temata_a_spol| length }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{# TODELETE #}
|
{# TODELETE #}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<th class='border-r'>Za číslo
|
<th class='border-r'>Za číslo
|
||||||
<th class='border-r'>Za ročník
|
<th class='border-r'>Za ročník
|
||||||
<th class='border-r'>Odjakživa
|
<th class='border-r'>Odjakživa
|
||||||
{% for rv in radky_vysledkovky %}
|
{% for rv in vysledkovka.radky_vysledkovky %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
|
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
|
||||||
<th class='border-r'>
|
<th class='border-r'>
|
||||||
|
@ -33,14 +33,12 @@
|
||||||
{{ rv.titul }}<sup>MM</sup>
|
{{ rv.titul }}<sup>MM</sup>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ rv.resitel.osoba.plne_jmeno }}
|
{{ rv.resitel.osoba.plne_jmeno }}
|
||||||
{% for b in rv.body_problemy_sezn %}
|
{% for b in rv.body_hlavni_problemy_seznam %}
|
||||||
<td class='border-r'>{{ b }}
|
<td class='border-r'>{{ b }}
|
||||||
|
|
||||||
{# TODELETE #}
|
|
||||||
{% for body_podproblemu in rv.body_podproblemy_iter.next %}
|
{% for body_podproblemu in rv.body_podproblemy_iter.next %}
|
||||||
<td class='border-r podproblem{{ forloop.parentloop.counter0 }} podproblem'>{{ body_podproblemu }}
|
<td class='border-r podproblem{{ forloop.parentloop.counter0 }} podproblem'>{{ body_podproblemu }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{# TODELETE #}
|
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<td class='border-r'>{{ rv.body_cislo }}
|
<td class='border-r'>{{ rv.body_cislo }}
|
||||||
|
@ -55,7 +53,7 @@
|
||||||
|
|
||||||
{# TODELETE #}
|
{# TODELETE #}
|
||||||
<script>
|
<script>
|
||||||
{% for p in problemy %}
|
{% for p in vysledkovka.temata_a_spol%}
|
||||||
diplayed{{ forloop.counter0 }} = false;
|
diplayed{{ forloop.counter0 }} = false;
|
||||||
$(".podproblem{{ forloop.counter0 }}").css("display", "none")
|
$(".podproblem{{ forloop.counter0 }}").css("display", "none")
|
||||||
$("#problem{{ forloop.counter0 }}")[0].addEventListener('click', podproblem{{ forloop.counter0 }});
|
$("#problem{{ forloop.counter0 }}")[0].addEventListener('click', podproblem{{ forloop.counter0 }});
|
||||||
|
@ -68,16 +66,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if ostatni %}
|
{% if vysledkovka.ostatni %}
|
||||||
diplayed{{ problemy | length }} = false;
|
diplayed{{ vysledkovka.temata_a_spol| length }} = false;
|
||||||
$(".podproblem{{ problemy | length }}").css("display", "none")
|
$(".podproblem{{ vysledkovka.temata_a_spol| length }}").css("display", "none")
|
||||||
$("#problem{{ problemy | length }}")[0].addEventListener('click', podproblem{{ problemy | length }});
|
$("#problem{{ vysledkovka.temata_a_spol| length }}")[0].addEventListener('click', podproblem{{ vysledkovka.temata_a_spol| length }});
|
||||||
function podproblem{{ problemy | length }}(event) {
|
function podproblem{{ vysledkovka.temata_a_spol| length }}(event) {
|
||||||
diplayed{{ problemy | length }} = !diplayed{{ problemy | length }};
|
diplayed{{ vysledkovka.temata_a_spol| length }} = !diplayed{{ vysledkovka.temata_a_spol| length }};
|
||||||
if (diplayed{{ problemy | length }}) {
|
if (diplayed{{ vysledkovka.temata_a_spol| length }}) {
|
||||||
$(".podproblem{{ problemy | length }}").css("display", "");
|
$(".podproblem{{ vysledkovka.temata_a_spol| length }}").css("display", "");
|
||||||
} else {
|
} else {
|
||||||
$(".podproblem{{ problemy | length }}").css("display", "none");
|
$(".podproblem{{ vysledkovka.temata_a_spol| length }}").css("display", "none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
<th class='border-r'>Jméno
|
<th class='border-r'>Jméno
|
||||||
<th class='border-r'>R.
|
<th class='border-r'>R.
|
||||||
<th class='border-r'>Odjakživa
|
<th class='border-r'>Odjakživa
|
||||||
{% for c in cisla %}
|
{% for c in vysledkovka.cisla_rocniku %}
|
||||||
<th class='border-r'><a href="{{ c.verejne_url }}">
|
<th class='border-r'><a href="{{ c.verejne_url }}">
|
||||||
{{c.rocnik.rocnik}}.{{ c.poradi }}</a>
|
{{c.rocnik.rocnik}}.{{ c.poradi }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<th class='border-r'>Celkem
|
<th class='border-r'>Celkem
|
||||||
|
|
||||||
{% for rv in radky_vysledkovky %}
|
{% for rv in vysledkovka.radky_vysledkovky %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
|
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
|
||||||
<th class='border-r'>
|
<th class='border-r'>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
{{ rv.resitel.osoba.plne_jmeno }}
|
{{ rv.resitel.osoba.plne_jmeno }}
|
||||||
<td class='border-r'>{{ rv.rocnik_resitele }}
|
<td class='border-r'>{{ rv.rocnik_resitele }}
|
||||||
<td class='border-r'>{{ rv.body_celkem_odjakziva }}
|
<td class='border-r'>{{ rv.body_celkem_odjakziva }}
|
||||||
{% for b in rv.body_cisla_sezn %}
|
{% for b in rv.body_cisla_seznam %}
|
||||||
<td class='border-r'>{{ b }}
|
<td class='border-r'>{{ b }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
|
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{% include "vysledkovky/vysledkovka_rocnik.html" with radky_vysledkovky=radky_vysledkovky_s_neverejnymi cisla=cisla_s_neverejnymi %}
|
|
|
@ -1,462 +1,451 @@
|
||||||
|
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:
|
|
||||||
sloupec_s_poradim (seznam stringů)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím
|
|
||||||
aktualni_poradi = 1
|
|
||||||
sloupec_s_poradim = []
|
|
||||||
|
|
||||||
# seskupíme seznam všech bodů podle hodnot
|
|
||||||
for index in range(0, len(setrizene_body)):
|
|
||||||
# pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme
|
|
||||||
# vypsat už jen prázdné místo, než dojdeme na správný řádek
|
|
||||||
if (index + 1) < aktualni_poradi:
|
|
||||||
sloupec_s_poradim.append("")
|
|
||||||
continue
|
|
||||||
velikost_skupiny = 0
|
|
||||||
# zjistíme počet po sobě jdoucích stejných hodnot
|
|
||||||
while setrizene_body[index] == setrizene_body[index + velikost_skupiny]:
|
|
||||||
velikost_skupiny = velikost_skupiny + 1
|
|
||||||
# na konci musíme ošetřit přetečení seznamu
|
|
||||||
if (index + velikost_skupiny) > len(setrizene_body) - 1:
|
|
||||||
break
|
|
||||||
# pokud je velikost skupiny 1, vypíšu pořadí
|
|
||||||
if velikost_skupiny == 1:
|
|
||||||
sloupec_s_poradim.append("{}.".format(aktualni_poradi))
|
|
||||||
# pokud je skupina větší, vypíšu rozsah
|
|
||||||
else:
|
|
||||||
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
|
|
||||||
return sloupec_s_poradim
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def body_resitelu(resitele, za, odjakziva=True, jen_verejne=False):
|
|
||||||
""" 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, 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ů
|
|
||||||
resitele_s_body = m.Resitel.objects.filter(id__in=resitele_id).annotate(
|
|
||||||
body=body_k_zapocteni)
|
|
||||||
# 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 0) for res in resitele_s_body}
|
|
||||||
return slovnik
|
|
||||||
|
|
||||||
class RadekVysledkovkyRocniku(object):
|
|
||||||
""" Obsahuje věci, které se hodí vědět při konstruování výsledkovky.
|
|
||||||
Umožňuje snazší práci v templatu (lepší, než seznam)."""
|
|
||||||
|
|
||||||
def __init__(self, poradi, resitel, body_cisla_sezn, body_rocnik, body_odjakziva, rok):
|
|
||||||
self.poradi = poradi
|
|
||||||
self.resitel = resitel
|
|
||||||
self.rocnik_resitele = resitel.rocnik(rok)
|
|
||||||
self.body_rocnik = body_rocnik
|
|
||||||
self.body_celkem_odjakziva = body_odjakziva
|
|
||||||
self.body_cisla_sezn = body_cisla_sezn
|
|
||||||
self.titul = resitel.get_titul(body_odjakziva)
|
|
||||||
|
|
||||||
def setrid_resitele_a_body(slov_resitel_body):
|
|
||||||
setrizeni_resitele_id = [dvojice[0] for dvojice in slov_resitel_body]
|
|
||||||
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 = []
|
|
||||||
i = 0
|
|
||||||
setrizeni_resitele_dict = {} # Tento slovnik se vyrab
|
|
||||||
for r in m.Resitel.objects.filter(id__in=setrizeni_resitele_id).select_related('osoba'):
|
|
||||||
setrizeni_resitele_dict[r.id] = r
|
|
||||||
|
|
||||||
for ar_id in setrizeni_resitele_id:
|
|
||||||
# seznam počtu bodů daného řešitele pro jednotlivá čísla
|
|
||||||
body_cisla_sezn = []
|
|
||||||
for cislo in cisla:
|
|
||||||
body_cisla_sezn.append(body_cisla_slov[cislo.id][ar_id])
|
|
||||||
|
|
||||||
# vytáhneme informace pro daného řešitele
|
|
||||||
radek = RadekVysledkovkyRocniku(
|
|
||||||
poradi[i], # pořadí
|
|
||||||
setrizeni_resitele_dict[ar_id], # řešitel (z id)
|
|
||||||
body_cisla_sezn, # seznam bodů za čísla
|
|
||||||
setrizene_body[i], # body za ročník (spočítané výše s pořadím)
|
|
||||||
resitel_odjakzivabody_slov[ar_id], # body odjakživa
|
|
||||||
rocnik) # ročník semináře pro získání ročníku řešitele
|
|
||||||
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
|
|
||||||
# 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 = {}
|
|
||||||
for hp in temata_a_spol:
|
|
||||||
hlavni_problemy_slovnik[hp.id] = {}
|
|
||||||
|
|
||||||
hlavni_problemy_slovnik[-1] = {}
|
|
||||||
|
|
||||||
# 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[ar.id] = ""
|
|
||||||
for hp in temata_a_spol:
|
|
||||||
slovnik = hlavni_problemy_slovnik[hp.id]
|
|
||||||
slovnik[ar.id] = ""
|
|
||||||
|
|
||||||
hlavni_problemy_slovnik[-1][ar.id] = ""
|
|
||||||
|
|
||||||
hodnoceni_do_cisla = m.Hodnoceni.objects.prefetch_related('problem', 'reseni', 'reseni__resitele').filter(cislo_body=cislo)
|
|
||||||
|
|
||||||
start = time.time()
|
|
||||||
|
|
||||||
for hodnoceni in hodnoceni_do_cisla:
|
|
||||||
prob = hodnoceni.problem
|
|
||||||
nadproblem = hlavni_problem(prob)
|
|
||||||
if ne_clanek_ne_konfera(nadproblem):
|
|
||||||
nadproblem_slovnik = hlavni_problemy_slovnik[nadproblem.id]
|
|
||||||
else:
|
|
||||||
nadproblem_slovnik = hlavni_problemy_slovnik[-1]
|
|
||||||
|
|
||||||
body = hodnoceni.body
|
|
||||||
|
|
||||||
# a mít více řešitelů
|
|
||||||
for resitel in hodnoceni.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)
|
|
||||||
end = time.time()
|
|
||||||
print("for cykly:", end-start)
|
|
||||||
return hlavni_problemy_slovnik, cislobody
|
|
||||||
|
|
||||||
|
|
||||||
def secti_body_za_cislo_podle_temat(cislo, aktivni_resitele, podproblemy=None, temata=None):
|
|
||||||
""" Spočítá u řešitelů body za číslo za úlohy v jednotlivých hlavních problémech (témata)."""
|
|
||||||
if temata is None:
|
|
||||||
temata = hlavni_problemy_f(problemy_cisla(cislo))
|
|
||||||
|
|
||||||
if podproblemy is None:
|
|
||||||
podproblemy_v_cislu(cislo, hlavni_problemy=temata)
|
|
||||||
|
|
||||||
body_slovnik = {}
|
|
||||||
for tema in temata:
|
|
||||||
body_slovnik[tema.id] = {}
|
|
||||||
for problem in podproblemy[tema.id]:
|
|
||||||
body_slovnik[tema.id][problem.id] = {}
|
|
||||||
body_slovnik[-1] = {}
|
|
||||||
for problem in podproblemy[-1]:
|
|
||||||
body_slovnik[-1][problem.id] = {}
|
|
||||||
|
|
||||||
# zakládání prázdných záznamů pro řešitele
|
|
||||||
for ar in aktivni_resitele:
|
|
||||||
for tema in temata:
|
|
||||||
for problem in podproblemy[tema.id]:
|
|
||||||
body_slovnik[tema.id][problem.id][ar.id] = ""
|
|
||||||
|
|
||||||
for problem in podproblemy[-1]:
|
|
||||||
body_slovnik[-1][problem.id][ar.id] = ""
|
|
||||||
|
|
||||||
temata = set(t.id for t in temata)
|
|
||||||
|
|
||||||
hodnoceni_do_cisla = m.Hodnoceni.objects.prefetch_related('problem', 'reseni', 'reseni__resitele').filter(cislo_body=cislo)
|
|
||||||
|
|
||||||
for hodnoceni in hodnoceni_do_cisla:
|
|
||||||
prob = hodnoceni.problem
|
|
||||||
nadproblem = hlavni_problem(prob)
|
|
||||||
if nadproblem.id in temata:
|
|
||||||
nadproblem_slovnik = body_slovnik[nadproblem.id]
|
|
||||||
else:
|
|
||||||
nadproblem_slovnik = body_slovnik[-1]
|
|
||||||
|
|
||||||
problem_slovnik = nadproblem_slovnik[prob.id]
|
|
||||||
|
|
||||||
body = hodnoceni.body
|
|
||||||
|
|
||||||
# a mít více řešitelů
|
|
||||||
for resitel in hodnoceni.reseni.resitele.all():
|
|
||||||
if resitel not in aktivni_resitele:
|
|
||||||
print("Skipping {}".format(resitel.id))
|
|
||||||
continue
|
|
||||||
pricti_body(problem_slovnik, resitel, body)
|
|
||||||
return body_slovnik
|
|
||||||
|
|
||||||
|
|
||||||
# TODELETE
|
|
||||||
class FixedIterator:
|
class FixedIterator:
|
||||||
def next(self):
|
def next(self):
|
||||||
return self.niter.__next__()
|
return self.niter.__next__()
|
||||||
|
|
||||||
def __init__(self, niter):
|
def __init__(self, niter):
|
||||||
self.niter = niter
|
self.niter = niter
|
||||||
# TODELETE
|
|
||||||
|
|
||||||
|
|
||||||
def data_vysledkovky_cisla(cislo):
|
def body_resitelu(
|
||||||
problemy = problemy_cisla(cislo)
|
za=None,
|
||||||
hlavni_problemy = hlavni_problemy_f(problemy)
|
do: m.Deadline = None,
|
||||||
## TODO možná chytřeji vybírat aktivní řešitele
|
od: m.Deadline = None,
|
||||||
# aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají
|
jen_verejne: bool = True,
|
||||||
# u alespoň jedné hodnoty něco jiného než NULL
|
resitele=None,
|
||||||
aktivni_resitele = list(resi_v_rocniku(cislo.rocnik))
|
null=0
|
||||||
|
) -> dict[int, int]:
|
||||||
|
filtr = Q()
|
||||||
|
|
||||||
# získáme body za číslo
|
if jen_verejne:
|
||||||
hlavni_problemy_slovnik, cislobody = secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy)
|
filtr &= Q(reseni__hodnoceni__deadline_body__verejna_vysledkovka=True)
|
||||||
|
|
||||||
# získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně
|
# Zjistíme, typ objektu v parametru "za"
|
||||||
resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo, aktivni_resitele, jen_verejne=True)
|
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)
|
||||||
|
|
||||||
# získáme body odjakživa
|
if do:
|
||||||
resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo, jen_verejne=True)
|
filtr &= Q(reseni__hodnoceni__deadline_body__lte=do)
|
||||||
|
|
||||||
# řešitelé setřídění podle bodů za číslo sestupně
|
if od:
|
||||||
setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn]
|
filtr &= Q(reseni__hodnoceni__deadline_body__gte=od)
|
||||||
|
|
||||||
# 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
|
resiteleQuery = m.Resitel.objects.all()
|
||||||
radky_vysledkovky = []
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
|
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
|
||||||
|
aktualni_poradi = 1
|
||||||
|
sloupec_s_poradim = []
|
||||||
|
|
||||||
|
# seskupíme seznam všech bodů podle hodnot
|
||||||
|
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 vypsat už jen prázdné místo, než dojdeme na správný řádek
|
||||||
|
if (index + 1) < aktualni_poradi:
|
||||||
|
sloupec_s_poradim.append("")
|
||||||
|
continue
|
||||||
|
velikost_skupiny = 0
|
||||||
|
# zjistíme počet po sobě jdoucích stejných hodnot
|
||||||
|
while self.setrizene_body[index] == self.setrizene_body[
|
||||||
|
index + velikost_skupiny]:
|
||||||
|
velikost_skupiny += 1
|
||||||
|
# na konci musíme ošetřit přetečení seznamu
|
||||||
|
if (index + velikost_skupiny) > len(self.setrizene_body) - 1:
|
||||||
|
break
|
||||||
|
# pokud je velikost skupiny 1, vypíšu pořadí
|
||||||
|
if velikost_skupiny == 1:
|
||||||
|
sloupec_s_poradim.append(f"{aktualni_poradi}.")
|
||||||
|
# pokud je skupina větší, vypíšu rozsah
|
||||||
|
else:
|
||||||
|
sloupec_s_poradim.append(
|
||||||
|
f"{aktualni_poradi}.–{aktualni_poradi + velikost_skupiny - 1}."
|
||||||
|
)
|
||||||
|
# zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno
|
||||||
|
aktualni_poradi += velikost_skupiny
|
||||||
|
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()
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def aktivni_resitele(self) -> list[m.Resitel]:
|
||||||
|
return list(resi_v_rocniku(self.rocnik))
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def cisla_rocniku(self) -> list[m.Cislo]:
|
||||||
|
return cisla_rocniku(self.rocnik, self.jen_verejne)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def body_za_cisla_slovnik(self) -> dict[int, dict[int, int]]:
|
||||||
|
body_cisla_slovnik = dict()
|
||||||
|
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:
|
||||||
|
""" Obsahuje věci, které se hodí vědět při konstruování výsledkovky.
|
||||||
|
Umožňuje snazší práci v templatu (lepší, než seznam)."""
|
||||||
|
|
||||||
|
def __init__(self, poradi, resitel, body_cisla_seznam, body_rocnik, body_odjakziva, rok):
|
||||||
|
self.poradi = poradi
|
||||||
|
self.resitel = resitel
|
||||||
|
self.rocnik_resitele = resitel.rocnik(rok)
|
||||||
|
self.body_rocnik = body_rocnik
|
||||||
|
self.body_celkem_odjakziva = body_odjakziva
|
||||||
|
self.body_cisla_seznam = body_cisla_seznam
|
||||||
|
self.titul = resitel.get_titul(body_odjakziva)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def radky_vysledkovky(self) -> list[RadekVysledkovkyRocniku]:
|
||||||
|
radky_vysledkovky = []
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
setrizeni_resitele_dict = dict()
|
||||||
|
for r in m.Resitel.objects.filter(
|
||||||
|
id__in=self.setrizeni_resitele_id
|
||||||
|
).select_related('osoba'):
|
||||||
|
setrizeni_resitele_dict[r.id] = r
|
||||||
|
|
||||||
|
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
|
||||||
|
body_cisla_seznam = []
|
||||||
|
for cislo in self.cisla_rocniku:
|
||||||
|
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
|
||||||
|
radek = self.RadekVysledkovkyRocniku(
|
||||||
|
poradi=self.poradi[i],
|
||||||
|
resitel=setrizeni_resitele_dict[ar_id],
|
||||||
|
body_cisla_seznam=body_cisla_seznam,
|
||||||
|
body_rocnik=self.setrizene_body[i],
|
||||||
|
body_odjakziva=self.resitel_body_odjakziva_slovnik[ar_id],
|
||||||
|
rok=self.rocnik) # ročník semináře pro získání ročníku řešitele
|
||||||
|
radky_vysledkovky.append(radek)
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return radky_vysledkovky
|
||||||
|
|
||||||
|
|
||||||
|
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[-1] = {}
|
||||||
|
|
||||||
|
# zakládání prázdných záznamů pro řešitele
|
||||||
|
cislobody = {}
|
||||||
|
for ar in self.aktivni_resitele:
|
||||||
|
# řešitele převedeme na řetězec pomocí unikátního id
|
||||||
|
cislobody[ar.id] = ""
|
||||||
|
for hp in self.temata_a_spol:
|
||||||
|
slovnik = hlavni_problemy_slovnik[hp.id]
|
||||||
|
slovnik[ar.id] = ""
|
||||||
|
|
||||||
|
hlavni_problemy_slovnik[-1][ar.id] = ""
|
||||||
|
|
||||||
|
hodnoceni_do_cisla = m.Hodnoceni.objects.prefetch_related(
|
||||||
|
'problem', 'reseni', 'reseni__resitele').filter(deadline_body__cislo=self.cislo)
|
||||||
|
|
||||||
|
for hodnoceni in hodnoceni_do_cisla:
|
||||||
|
prob = hodnoceni.problem
|
||||||
|
nadproblem = hlavni_problem(prob)
|
||||||
|
if self.ne_clanek_ne_konfera(nadproblem):
|
||||||
|
nadproblem_slovnik = hlavni_problemy_slovnik[nadproblem.id]
|
||||||
|
else:
|
||||||
|
nadproblem_slovnik = hlavni_problemy_slovnik[-1]
|
||||||
|
|
||||||
|
body = hodnoceni.body
|
||||||
|
|
||||||
|
# a mít více řešitelů
|
||||||
|
for resitel in hodnoceni.reseni.resitele.all():
|
||||||
|
if resitel not in self.aktivni_resitele:
|
||||||
|
continue
|
||||||
|
self.pricti_body(cislobody, resitel, body)
|
||||||
|
self.pricti_body(nadproblem_slovnik, resitel, body)
|
||||||
|
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]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def body_za_cislo(self) -> dict[int, str]:
|
||||||
|
return self.problemy_s_body_za_cislo[1]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
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 = {}
|
||||||
|
for tema in self.temata_a_spol:
|
||||||
|
body_slovnik[tema.id] = {}
|
||||||
|
for problem in self.podproblemy[tema.id]:
|
||||||
|
body_slovnik[tema.id][problem.id] = {}
|
||||||
|
body_slovnik[-1] = {}
|
||||||
|
for problem in self.podproblemy[-1]:
|
||||||
|
body_slovnik[-1][problem.id] = {}
|
||||||
|
|
||||||
|
# zakládání prázdných záznamů pro řešitele
|
||||||
|
for ar in self.aktivni_resitele:
|
||||||
|
for tema in self.temata_a_spol:
|
||||||
|
for problem in self.podproblemy[tema.id]:
|
||||||
|
body_slovnik[tema.id][problem.id][ar.id] = ""
|
||||||
|
|
||||||
|
for problem in self.podproblemy[-1]:
|
||||||
|
body_slovnik[-1][problem.id][ar.id] = ""
|
||||||
|
|
||||||
|
temata = set(t.id for t in self.temata_a_spol)
|
||||||
|
|
||||||
|
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:
|
||||||
|
prob = hodnoceni.problem
|
||||||
|
nadproblem = hlavni_problem(prob)
|
||||||
|
if nadproblem.id in temata:
|
||||||
|
nadproblem_slovnik = body_slovnik[nadproblem.id]
|
||||||
|
else:
|
||||||
|
nadproblem_slovnik = body_slovnik[-1]
|
||||||
|
|
||||||
|
problem_slovnik = nadproblem_slovnik[prob.id]
|
||||||
|
|
||||||
|
body = hodnoceni.body
|
||||||
|
|
||||||
|
# a mít více řešitelů
|
||||||
|
for resitel in hodnoceni.reseni.resitele.all():
|
||||||
|
if resitel not in self.aktivni_resitele:
|
||||||
|
continue
|
||||||
|
self.pricti_body(problem_slovnik, resitel, body)
|
||||||
|
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)."""
|
||||||
|
|
||||||
|
def __init__(self, poradi, resitel, body_hlavni_problemy_seznam, 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_hlavni_problemy_seznam = body_hlavni_problemy_seznam
|
||||||
|
self.titul = resitel.get_titul(body_odjakziva)
|
||||||
|
self.body_podproblemy = body_podproblemy
|
||||||
|
self.body_podproblemy_iter = body_podproblemy_iter
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def radky_vysledkovky(self) -> list[RadekVysledkovkyCisla]:
|
||||||
|
# vytvoříme jednotlivé sloupce výsledkovky
|
||||||
|
radky_vysledkovky = []
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
setrizeni_resitele_slovnik = {}
|
||||||
|
setrizeni_resitele = m.Resitel.objects.filter(id__in=self.setrizeni_resitele_id).select_related('osoba')
|
||||||
|
|
||||||
|
for r in setrizeni_resitele:
|
||||||
|
setrizeni_resitele_slovnik[r.id] = r
|
||||||
|
|
||||||
|
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
|
||||||
|
body_problemy = []
|
||||||
|
body_podproblemy = []
|
||||||
|
for hp in self.temata_a_spol:
|
||||||
|
body_problemy.append(self.hlavni_problemy_slovnik[hp.id][ar_id])
|
||||||
|
body_podproblemy.append([
|
||||||
|
self.problemy_slovnik[hp.id][it.id][ar_id]
|
||||||
|
for it in self.podproblemy[hp.id]
|
||||||
|
])
|
||||||
|
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
|
||||||
|
radek = self.RadekVysledkovkyCisla(
|
||||||
|
poradi=self.poradi[i],
|
||||||
|
resitel=setrizeni_resitele_slovnik[ar_id],
|
||||||
|
body_hlavni_problemy_seznam=body_problemy,
|
||||||
|
body_cislo=self.body_za_cislo[ar_id],
|
||||||
|
body_rocnik=self.setrizene_body[i],
|
||||||
|
body_odjakziva=self.resitel_body_odjakziva_slovnik[ar_id],
|
||||||
|
rok=self.rocnik,
|
||||||
|
body_podproblemy=body_podproblemy, # body všech podproblémů
|
||||||
|
body_podproblemy_iter=FixedIterator(body_podproblemy.__iter__())
|
||||||
|
) # ročník semináře pro zjištění ročníku řešitele
|
||||||
|
radky_vysledkovky.append(radek)
|
||||||
|
i += 1
|
||||||
|
return radky_vysledkovky
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
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
|
||||||
|
# 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):
|
def ne_clanek_ne_konfera(problem):
|
||||||
|
inst = problem.get_real_instance()
|
||||||
return not(isinstance(problem.get_real_instance(), m.Clanek) or isinstance(problem.get_real_instance(), m.Konfera))
|
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))
|
|
||||||
|
|
||||||
# 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 = m.Resitel.objects.filter(id__in=setrizeni_resitele_id).select_related('osoba')
|
|
||||||
for r in setrizeni_resitele:
|
|
||||||
setrizeni_resitele_slovnik[r.id] = r
|
|
||||||
|
|
||||||
for ar_id in setrizeni_resitele_id:
|
|
||||||
# získáme seznam bodů za problémy pro daného řešitele
|
|
||||||
body_problemy = []
|
|
||||||
body_podproblemy = []
|
|
||||||
for hp in temata_a_spol:
|
|
||||||
body_problemy.append(hlavni_problemy_slovnik[hp.id][ar_id])
|
|
||||||
body_podproblemy.append([problemy_slovnik[hp.id][it.id][ar_id] for it in podproblemy[hp.id]])
|
|
||||||
if je_nejake_ostatni:
|
|
||||||
body_problemy.append(hlavni_problemy_slovnik[-1][ar_id])
|
|
||||||
body_podproblemy.append([problemy_slovnik[-1][it.id][ar_id] for it in podproblemy[-1]])
|
|
||||||
# vytáhneme informace pro daného řešitele
|
|
||||||
radek = RadekVysledkovkyCisla(
|
|
||||||
poradi[i], # pořadí
|
|
||||||
setrizeni_resitele_slovnik[ar_id], # řešitel (z id)
|
|
||||||
body_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
|
|
||||||
cislo.rocnik,
|
|
||||||
body_podproblemy, # body všech podproblémů
|
|
||||||
FixedIterator(body_podproblemy.__iter__()) # TODELETE
|
|
||||||
) # ročník semináře pro zjištění ročníku řešitele
|
|
||||||
radky_vysledkovky.append(radek)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# vytahané informace předáváme do kontextu
|
|
||||||
pt = [podproblemy[it.id] for it in temata_a_spol]+[podproblemy[-1]]
|
|
||||||
radky_vysledkovky = [radek for radek in radky_vysledkovky if radek.body_rocnik > 0]
|
|
||||||
return (
|
|
||||||
radky_vysledkovky,
|
|
||||||
temata_a_spol,
|
|
||||||
je_nejake_ostatni,
|
|
||||||
pt,
|
|
||||||
FixedIterator(pt.__iter__())
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
from .utils import data_vysledkovky_cisla, \
|
|
||||||
data_vysledkovky_rocniku
|
|
||||||
|
|
||||||
|
|
||||||
def vysledkovka_cisla(cislo, context=None):
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
context['cislo'] = cislo
|
|
||||||
|
|
||||||
(
|
|
||||||
context['radky_vysledkovky'],
|
|
||||||
context['problemy'],
|
|
||||||
context['ostatni'],
|
|
||||||
context['podproblemy'],
|
|
||||||
context['podproblemy_iter']
|
|
||||||
) = data_vysledkovky_cisla(cislo)
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def vysledkovka_rocniku(rocnik, context=None, request=None, sneverejnou=False):
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
|
|
||||||
(
|
|
||||||
context['radky_vysledkovky'],
|
|
||||||
context['cisla']
|
|
||||||
) = data_vysledkovky_rocniku(rocnik)
|
|
||||||
|
|
||||||
context['vysledkovka'] = len(context['cisla']) != 0
|
|
||||||
|
|
||||||
if sneverejnou and request and request.user.je_org:
|
|
||||||
(
|
|
||||||
context['radky_vysledkovky_s_neverejnymi'],
|
|
||||||
context['cisla_s_neverejnymi']
|
|
||||||
) = data_vysledkovky_rocniku(rocnik, jen_verejne=False)
|
|
||||||
|
|
||||||
return context
|
|
Loading…
Reference in a new issue