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,223 +1,434 @@ | ||||||
|  | import abc | ||||||
|  | from functools import cached_property | ||||||
|  | 
 | ||||||
| import seminar.models as m | import seminar.models as m | ||||||
| from django.db.models import Q, Sum, Count | from django.db.models import Q, Sum | ||||||
| from seminar.utils import aktivniResitele, resi_v_rocniku, cisla_rocniku, hlavni_problem, hlavni_problemy_f, problemy_cisla, podproblemy_v_cislu | from seminar.utils import resi_v_rocniku, cisla_rocniku, hlavni_problem,\ | ||||||
| import time | 	hlavni_problemy_f, problemy_cisla, podproblemy_v_cislu | ||||||
| 
 | 
 | ||||||
| ROCNIK_ZRUSENI_TEMAT = 25 | ROCNIK_ZRUSENI_TEMAT = 25 | ||||||
| 
 | 
 | ||||||
| def sloupec_s_poradim(setrizene_body): |  | ||||||
| 	""" |  | ||||||
| 	Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník  |  | ||||||
| 	vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.), |  | ||||||
| 	podle toho, jak jdou za sebou ve výsledkovce. |  | ||||||
| 	Parametr: |  | ||||||
| 		setrizene_body (seznam integerů): sestupně setřízená čísla |  | ||||||
| 
 | 
 | ||||||
| 	Výstup: | class FixedIterator: | ||||||
| 		sloupec_s_poradim (seznam stringů) | 	def next(self): | ||||||
| 	""" | 		return self.niter.__next__() | ||||||
| 
 | 
 | ||||||
|  | 	def __init__(self, niter): | ||||||
|  | 		self.niter = niter | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def body_resitelu( | ||||||
|  | 		za=None, | ||||||
|  | 		do: m.Deadline = None, | ||||||
|  | 		od: m.Deadline = None, | ||||||
|  | 		jen_verejne: bool = True, | ||||||
|  | 		resitele=None, | ||||||
|  | 		null=0 | ||||||
|  | ) -> dict[int, int]: | ||||||
|  | 	filtr = Q() | ||||||
|  | 
 | ||||||
|  | 	if jen_verejne: | ||||||
|  | 		filtr &= Q(reseni__hodnoceni__deadline_body__verejna_vysledkovka=True) | ||||||
|  | 
 | ||||||
|  | 	# Zjistíme, typ objektu v parametru "za" | ||||||
|  | 	if isinstance(za, m.Rocnik): | ||||||
|  | 		filtr &= Q(reseni__hodnoceni__deadline_body__cislo__rocnik=za) | ||||||
|  | 	elif isinstance(za, m.Cislo): | ||||||
|  | 		filtr &= Q(reseni__hodnoceni__deadline_body__cislo=za) | ||||||
|  | 
 | ||||||
|  | 	if do: | ||||||
|  | 		filtr &= Q(reseni__hodnoceni__deadline_body__lte=do) | ||||||
|  | 
 | ||||||
|  | 	if od: | ||||||
|  | 		filtr &= Q(reseni__hodnoceni__deadline_body__gte=od) | ||||||
|  | 
 | ||||||
|  | 	resiteleQuery = m.Resitel.objects.all() | ||||||
|  | 
 | ||||||
|  | 	if resitele is not None: | ||||||
|  | 		resitele_id = [r.id for r in resitele] | ||||||
|  | 		resiteleQuery = resiteleQuery.filter(id__in=resitele_id) | ||||||
|  | 
 | ||||||
|  | 	# Přidáme ke každému řešiteli údaj ".body" se součtem jejich bodů | ||||||
|  | 	resitele_s_body = resiteleQuery.annotate( | ||||||
|  | 		body=Sum('reseni__hodnoceni__body', filter=filtr)) | ||||||
|  | 
 | ||||||
|  | 	# Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník | ||||||
|  | 	# indexovaný řešitelským id obsahující body. | ||||||
|  | 	# Pokud jsou body None, nahradíme za 0. | ||||||
|  | 	slovnik = { | ||||||
|  | 		int(res.id): (res.body if res.body else null) for res in resitele_s_body | ||||||
|  | 	} | ||||||
|  | 	return slovnik | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Vysledkovka(abc.ABC): | ||||||
|  | 	jen_verejne: bool | ||||||
|  | 	rocnik: m.Rocnik | ||||||
|  | 	do_deadlinu: m.Deadline | ||||||
|  | 
 | ||||||
|  | 	@property | ||||||
|  | 	@abc.abstractmethod | ||||||
|  | 	def aktivni_resitele(self) -> list[m.Resitel]: | ||||||
|  | 		... | ||||||
|  | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def resitele_s_body_za_rocnik_setrizeny_seznam(self) -> list[tuple[int, int]]: | ||||||
|  | 		# spočítáme všem řešitelům jejich body za ročník | ||||||
|  | 		resitel_body_za_rocnik_slovnik = body_resitelu( | ||||||
|  | 			resitele=self.aktivni_resitele, | ||||||
|  | 			za=self.rocnik, | ||||||
|  | 			jen_verejne=self.jen_verejne, | ||||||
|  | 			do=self.do_deadlinu | ||||||
|  | 		) | ||||||
|  | 
 | ||||||
|  | 		# zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně | ||||||
|  | 		resitele_s_body_za_rocnik_setrizeny_seznam = sorted( | ||||||
|  | 			resitel_body_za_rocnik_slovnik.items(), | ||||||
|  | 			key=lambda x: x[1], reverse=True | ||||||
|  | 		) | ||||||
|  | 
 | ||||||
|  | 		return resitele_s_body_za_rocnik_setrizeny_seznam | ||||||
|  | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def body_za_rocnik_seznamy(self) -> tuple[list[int], list[int]]: | ||||||
|  | 		if len(self.resitele_s_body_za_rocnik_setrizeny_seznam) == 0: | ||||||
|  | 			return [], [] | ||||||
|  | 		return tuple(zip(*self.resitele_s_body_za_rocnik_setrizeny_seznam)) | ||||||
|  | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def setrizeni_resitele_id(self) -> list[int]: | ||||||
|  | 		return self.body_za_rocnik_seznamy[0] | ||||||
|  | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def setrizene_body(self) -> list[int]: | ||||||
|  | 		return self.body_za_rocnik_seznamy[1] | ||||||
|  | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def resitel_body_odjakziva_slovnik(self) -> dict[int, int]: | ||||||
|  | 		return body_resitelu(jen_verejne=self.jen_verejne, do=self.do_deadlinu) | ||||||
|  | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def poradi(self): | ||||||
| 		# ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím | 		# ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím | ||||||
| 		aktualni_poradi = 1 | 		aktualni_poradi = 1 | ||||||
| 		sloupec_s_poradim = [] | 		sloupec_s_poradim = [] | ||||||
| 
 | 
 | ||||||
| 		# seskupíme seznam všech bodů podle hodnot | 		# seskupíme seznam všech bodů podle hodnot | ||||||
| 	for index in range(0, len(setrizene_body)): | 		for index in range(0, len(self.setrizene_body)): | ||||||
| 		# pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme | 			# pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah | ||||||
| 		# vypsat už jen prázdné místo, než dojdeme na správný řádek | 			# a chceme vypsat už jen prázdné místo, než dojdeme na správný řádek | ||||||
| 			if (index + 1) < aktualni_poradi: | 			if (index + 1) < aktualni_poradi: | ||||||
| 				sloupec_s_poradim.append("") | 				sloupec_s_poradim.append("") | ||||||
| 				continue | 				continue | ||||||
| 			velikost_skupiny = 0 | 			velikost_skupiny = 0 | ||||||
| 			# zjistíme počet po sobě jdoucích stejných hodnot | 			# zjistíme počet po sobě jdoucích stejných hodnot | ||||||
| 		while setrizene_body[index] == setrizene_body[index + velikost_skupiny]: | 			while self.setrizene_body[index] == self.setrizene_body[ | ||||||
| 			velikost_skupiny = velikost_skupiny + 1 | 				index + velikost_skupiny]: | ||||||
|  | 				velikost_skupiny += 1 | ||||||
| 				# na konci musíme ošetřit přetečení seznamu | 				# na konci musíme ošetřit přetečení seznamu | ||||||
| 			if (index + velikost_skupiny) > len(setrizene_body) - 1: | 				if (index + velikost_skupiny) > len(self.setrizene_body) - 1: | ||||||
| 					break | 					break | ||||||
| 			# pokud je velikost skupiny 1, vypíšu pořadí | 			# pokud je velikost skupiny 1, vypíšu pořadí | ||||||
| 			if velikost_skupiny == 1: | 			if velikost_skupiny == 1: | ||||||
| 			sloupec_s_poradim.append("{}.".format(aktualni_poradi)) | 				sloupec_s_poradim.append(f"{aktualni_poradi}.") | ||||||
| 			# pokud je skupina větší, vypíšu rozsah | 			# pokud je skupina větší, vypíšu rozsah | ||||||
| 			else: | 			else: | ||||||
| 			sloupec_s_poradim.append("{}.–{}.".format(aktualni_poradi,  | 				sloupec_s_poradim.append( | ||||||
| 						aktualni_poradi+velikost_skupiny-1)) | 					f"{aktualni_poradi}.–{aktualni_poradi + velikost_skupiny - 1}." | ||||||
|  | 				) | ||||||
| 			# zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno | 			# zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno | ||||||
| 		aktualni_poradi = aktualni_poradi + velikost_skupiny | 			aktualni_poradi += velikost_skupiny | ||||||
| 		return sloupec_s_poradim | 		return sloupec_s_poradim | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class VysledkovkaRocniku(Vysledkovka): | ||||||
| 
 | 
 | ||||||
|  | 	def __init__(self, rocnik: m.Rocnik, jen_verejne: bool = True): | ||||||
|  | 		self.rocnik = rocnik | ||||||
|  | 		self.jen_verejne = jen_verejne | ||||||
|  | 		self.do_deadlinu = m.Deadline.objects.filter(cislo__rocnik=rocnik).last() | ||||||
| 
 | 
 | ||||||
| def body_resitelu(resitele, za, odjakziva=True, jen_verejne=False): | 	@cached_property | ||||||
| 	""" Funkce počítající počty bodů pro zadané řešitele,  | 	def aktivni_resitele(self) -> list[m.Resitel]: | ||||||
| 	buď odjakživa do daného ročníku/čísla anebo za daný ročník/číslo. | 		return list(resi_v_rocniku(self.rocnik)) | ||||||
| 	Parametry: |  | ||||||
| 		resitele (seznam obsahující položky typu Resitel): aktivní řešitelé |  | ||||||
| 		za (Rocnik/Cislo): za co se mají počítat body  |  | ||||||
| 			(generování starších výsledkovek) |  | ||||||
| 		odjakziva (bool): zda se mají počítat body odjakživa, nebo jen za číslo/ročník |  | ||||||
| 			zadané v "za" |  | ||||||
| 	Výstup: |  | ||||||
| 		slovník (Resitel.id):body |  | ||||||
| 	"""		 |  | ||||||
| 	resitele_id = [r.id for r in resitele] |  | ||||||
| 	# Zjistíme, typ objektu v parametru "za" |  | ||||||
| 	if isinstance(za, m.Rocnik): |  | ||||||
| 		cislo = None |  | ||||||
| 		rocnik = za |  | ||||||
| 		rok = rocnik.prvni_rok |  | ||||||
| 	elif isinstance(za, m.Cislo): |  | ||||||
| 		cislo = za |  | ||||||
| 		rocnik = None |  | ||||||
| 		rok = cislo.rocnik.prvni_rok |  | ||||||
| 	else: |  | ||||||
| 		assert True, "body_resitelu: za není ani číslo ani ročník."	 |  | ||||||
| 
 | 
 | ||||||
|  | 	@cached_property | ||||||
|  | 	def cisla_rocniku(self) -> list[m.Cislo]: | ||||||
|  | 		return cisla_rocniku(self.rocnik, self.jen_verejne) | ||||||
| 
 | 
 | ||||||
| 	# Kvůli rychlosti používáme sčítáme body už v databázi, viz  | 	@cached_property | ||||||
| 	# https://docs.djangoproject.com/en/3.0/topics/db/aggregation/,  | 	def body_za_cisla_slovnik(self) -> dict[int, dict[int, int]]: | ||||||
| 	# sekce Filtering on annotations (protože potřebujeme filtrovat výsledky | 		body_cisla_slovnik = dict() | ||||||
| 	# jen do nějakého data, abychom uměli správně nagenerovat výsledkovky i  | 		for cislo in self.cisla_rocniku: | ||||||
| 	# za historická čísla. | 			# 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 | ||||||
| 
 | 
 | ||||||
| 	# Níže se vytváří dotaz na součet bodů za správně vyfiltrovaná hodnocení,  | 	class RadekVysledkovkyRocniku: | ||||||
| 	# 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. | 		""" Obsahuje věci, které se hodí vědět při konstruování výsledkovky. | ||||||
| 		Umožňuje snazší práci v templatu (lepší, než seznam).""" | 		Umožňuje snazší práci v templatu (lepší, než seznam).""" | ||||||
| 
 | 
 | ||||||
| 	def __init__(self, poradi, resitel, body_cisla_sezn, body_rocnik, body_odjakziva, rok): | 		def __init__(self, poradi, resitel, body_cisla_seznam, body_rocnik, body_odjakziva, rok): | ||||||
| 			self.poradi = poradi | 			self.poradi = poradi | ||||||
| 			self.resitel = resitel | 			self.resitel = resitel | ||||||
| 			self.rocnik_resitele = resitel.rocnik(rok) | 			self.rocnik_resitele = resitel.rocnik(rok) | ||||||
| 			self.body_rocnik = body_rocnik | 			self.body_rocnik = body_rocnik | ||||||
| 			self.body_celkem_odjakziva = body_odjakziva | 			self.body_celkem_odjakziva = body_odjakziva | ||||||
| 		self.body_cisla_sezn = body_cisla_sezn | 			self.body_cisla_seznam = body_cisla_seznam | ||||||
| 			self.titul = resitel.get_titul(body_odjakziva) | 			self.titul = resitel.get_titul(body_odjakziva) | ||||||
| 
 | 
 | ||||||
| def setrid_resitele_a_body(slov_resitel_body): | 	@cached_property | ||||||
| 	setrizeni_resitele_id = [dvojice[0] for dvojice in slov_resitel_body] | 	def radky_vysledkovky(self) -> list[RadekVysledkovkyRocniku]: | ||||||
| 	setrizene_body = [dvojice[1] for dvojice in slov_resitel_body] |  | ||||||
| 	return setrizeni_resitele_id,  setrizene_body |  | ||||||
| 
 |  | ||||||
| def data_vysledkovky_rocniku(rocnik, jen_verejne=True): |  | ||||||
| 	""" Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve |  | ||||||
| 	formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" |  | ||||||
| 	""" |  | ||||||
| 	 |  | ||||||
| 	start = time.time() |  | ||||||
| 
 |  | ||||||
| 	## TODO možná chytřeji vybírat aktivní řešitele |  | ||||||
| 	# aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají  |  | ||||||
| 	# u alespoň jedné hodnoty něco jiného než NULL |  | ||||||
| 	aktivni_resitele = list(resi_v_rocniku(rocnik)) |  | ||||||
| 	cisla = cisla_rocniku(rocnik, jen_verejne) |  | ||||||
| 	body_cisla_slov = {} |  | ||||||
| 	for cislo in cisla: |  | ||||||
| 		# získáme body za číslo |  | ||||||
| 		_, cislobody = secti_body_za_cislo(cislo, aktivni_resitele) |  | ||||||
| 		body_cisla_slov[cislo.id] = cislobody |  | ||||||
| 
 |  | ||||||
| 	# získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně |  | ||||||
| 	resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele, jen_verejne=jen_verejne) |  | ||||||
| 
 |  | ||||||
| 	# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší |  | ||||||
| 	setrizeni_resitele_id, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn) |  | ||||||
| 	poradi = sloupec_s_poradim(setrizene_body) |  | ||||||
| 
 |  | ||||||
| 	# získáme body odjakživa |  | ||||||
| 	resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, rocnik, jen_verejne=jen_verejne) |  | ||||||
| 
 |  | ||||||
| 	# vytvoříme jednotlivé sloupce výsledkovky |  | ||||||
| 		radky_vysledkovky = [] | 		radky_vysledkovky = [] | ||||||
|  | 
 | ||||||
| 		i = 0 | 		i = 0 | ||||||
| 	setrizeni_resitele_dict = {} # Tento slovnik se vyrab | 		setrizeni_resitele_dict = dict() | ||||||
| 	for r in m.Resitel.objects.filter(id__in=setrizeni_resitele_id).select_related('osoba'): | 		for r in m.Resitel.objects.filter( | ||||||
|  | 				id__in=self.setrizeni_resitele_id | ||||||
|  | 		).select_related('osoba'): | ||||||
| 			setrizeni_resitele_dict[r.id] = r | 			setrizeni_resitele_dict[r.id] = r | ||||||
| 
 | 
 | ||||||
| 	for ar_id in setrizeni_resitele_id: | 		for ar_id in self.setrizeni_resitele_id: | ||||||
|  | 			if self.setrizene_body[i] > 0: | ||||||
| 				# seznam počtu bodů daného řešitele pro jednotlivá čísla | 				# seznam počtu bodů daného řešitele pro jednotlivá čísla | ||||||
| 		body_cisla_sezn = [] | 				body_cisla_seznam = [] | ||||||
| 		for cislo in cisla: | 				for cislo in self.cisla_rocniku: | ||||||
| 			body_cisla_sezn.append(body_cisla_slov[cislo.id][ar_id]) | 					body_cisla_seznam.append(self.body_za_cisla_slovnik[cislo.id][ar_id]) | ||||||
| 
 | 
 | ||||||
|  | 				# Pokud řešitel dostal nějaké body | ||||||
|  | 				if self.resitele_s_body_za_rocnik_setrizeny_seznam[i] != 0: | ||||||
| 					# vytáhneme informace pro daného řešitele | 					# vytáhneme informace pro daného řešitele | ||||||
| 		radek = RadekVysledkovkyRocniku( | 					radek = self.RadekVysledkovkyRocniku( | ||||||
| 			poradi[i], # pořadí | 						poradi=self.poradi[i], | ||||||
| 			setrizeni_resitele_dict[ar_id], # řešitel (z id) | 						resitel=setrizeni_resitele_dict[ar_id], | ||||||
| 			body_cisla_sezn, # seznam bodů za čísla | 						body_cisla_seznam=body_cisla_seznam, | ||||||
| 			setrizene_body[i], # body za ročník (spočítané výše s pořadím) | 						body_rocnik=self.setrizene_body[i], | ||||||
| 			resitel_odjakzivabody_slov[ar_id], # body odjakživa | 						body_odjakziva=self.resitel_body_odjakziva_slovnik[ar_id], | ||||||
| 			rocnik) # ročník semináře pro získání ročníku řešitele | 						rok=self.rocnik)  # ročník semináře pro získání ročníku řešitele | ||||||
| 					radky_vysledkovky.append(radek) | 					radky_vysledkovky.append(radek) | ||||||
|  | 
 | ||||||
| 			i += 1 | 			i += 1 | ||||||
| 
 | 
 | ||||||
| 	end = time.time() | 		return radky_vysledkovky | ||||||
| 	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): | 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. | 		"""Obsahuje věci, které se hodí vědět při konstruování výsledkovky. | ||||||
| 		Umožňuje snazší práci v templatu (lepší, než seznam).""" | 		Umožňuje snazší práci v templatu (lepší, než seznam).""" | ||||||
| 
 | 
 | ||||||
| 	def __init__(self, poradi, resitel, body_problemy_sezn, | 		def __init__(self, poradi, resitel, body_hlavni_problemy_seznam, body_cislo, body_rocnik, body_odjakziva, rok, body_podproblemy, body_podproblemy_iter): | ||||||
| 				body_cislo, body_rocnik, body_odjakziva, rok, body_podproblemy, body_podproblemy_iter): |  | ||||||
| 			self.resitel = resitel | 			self.resitel = resitel | ||||||
| 			self.rocnik_resitele = resitel.rocnik(rok) | 			self.rocnik_resitele = resitel.rocnik(rok) | ||||||
| 			self.body_cislo = body_cislo | 			self.body_cislo = body_cislo | ||||||
| 			self.body_rocnik = body_rocnik | 			self.body_rocnik = body_rocnik | ||||||
| 			self.body_celkem_odjakziva = body_odjakziva | 			self.body_celkem_odjakziva = body_odjakziva | ||||||
| 			self.poradi = poradi | 			self.poradi = poradi | ||||||
| 		self.body_problemy_sezn = body_problemy_sezn | 			self.body_hlavni_problemy_seznam = body_hlavni_problemy_seznam | ||||||
| 			self.titul = resitel.get_titul(body_odjakziva) | 			self.titul = resitel.get_titul(body_odjakziva) | ||||||
| 			self.body_podproblemy = body_podproblemy | 			self.body_podproblemy = body_podproblemy | ||||||
| 		self.body_podproblemy_iter = body_podproblemy_iter  # TODELETE | 			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 | ||||||
| 
 | 
 | ||||||
| def pricti_body(slovnik, resitel, body): | 		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. """ | 		""" Přiřazuje danému řešiteli body do slovníku. """ | ||||||
| 		# testujeme na None (""), pokud je to první řešení | 		# testujeme na None (""), pokud je to první řešení | ||||||
| 		# daného řešitele, předěláme na 0 | 		# daného řešitele, předěláme na 0 | ||||||
|  | @ -234,229 +445,7 @@ def pricti_body(slovnik, resitel, body): | ||||||
| 
 | 
 | ||||||
| 		slovnik[resitel.id] += body | 		slovnik[resitel.id] += body | ||||||
| 
 | 
 | ||||||
| def secti_body_za_rocnik(za, aktivni_resitele, jen_verejne): | 	@staticmethod | ||||||
| 	""" 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): | 	def ne_clanek_ne_konfera(problem): | ||||||
| 		inst = problem.get_real_instance() | 		inst = problem.get_real_instance() | ||||||
| 		return not(isinstance(inst, m.Clanek) or isinstance(inst, 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)) |  | ||||||
| 
 |  | ||||||
| 	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: |  | ||||||
| 	def next(self): |  | ||||||
| 		return self.niter.__next__() |  | ||||||
| 
 |  | ||||||
| 	def __init__(self, niter): |  | ||||||
| 		self.niter = niter |  | ||||||
| # TODELETE |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def data_vysledkovky_cisla(cislo): |  | ||||||
| 	problemy = problemy_cisla(cislo) |  | ||||||
| 	hlavni_problemy = hlavni_problemy_f(problemy) |  | ||||||
| 	## TODO možná chytřeji vybírat aktivní řešitele |  | ||||||
| 	# aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají  |  | ||||||
| 	# u alespoň jedné hodnoty něco jiného než NULL |  | ||||||
| 	aktivni_resitele = list(resi_v_rocniku(cislo.rocnik)) |  | ||||||
| 
 |  | ||||||
| 	# získáme body za číslo |  | ||||||
| 	hlavni_problemy_slovnik, cislobody = secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy) |  | ||||||
| 
 |  | ||||||
| 	# získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně |  | ||||||
| 	resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo, aktivni_resitele, jen_verejne=True) |  | ||||||
| 
 |  | ||||||
| 	# získáme body odjakživa |  | ||||||
| 	resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo, jen_verejne=True) |  | ||||||
| 
 |  | ||||||
| 	# řešitelé setřídění podle bodů za číslo sestupně |  | ||||||
| 	setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] |  | ||||||
| 			 |  | ||||||
| 	# spočítáme pořadí řešitelů |  | ||||||
| 	setrizeni_resitele_body = [dvojice[1] for dvojice in resitel_rocnikbody_sezn] |  | ||||||
| 	poradi = sloupec_s_poradim(setrizeni_resitele_body) |  | ||||||
| 
 |  | ||||||
| 	# vytvoříme jednotlivé sloupce výsledkovky |  | ||||||
| 	radky_vysledkovky = [] |  | ||||||
| 	i = 0 |  | ||||||
| 
 |  | ||||||
| 	def ne_clanek_ne_konfera(problem): |  | ||||||
| 		 |  | ||||||
| 		return not(isinstance(problem.get_real_instance(), m.Clanek) or isinstance(problem.get_real_instance(), m.Konfera)) |  | ||||||
| 
 |  | ||||||
| 	if cislo.rocnik.rocnik < ROCNIK_ZRUSENI_TEMAT: |  | ||||||
| 		temata_a_spol = hlavni_problemy |  | ||||||
| 	else: |  | ||||||
| 		temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy)) |  | ||||||
| 
 |  | ||||||
| 	# získáme body u jednotlivých témat |  | ||||||
| 	podproblemy = podproblemy_v_cislu(cislo, problemy, temata_a_spol) |  | ||||||
| 	problemy_slovnik = secti_body_za_cislo_podle_temat(cislo, aktivni_resitele, podproblemy, temata_a_spol) |  | ||||||
| 
 |  | ||||||
| 	# def not_empty(value): |  | ||||||
| 	# 	return value != '' |  | ||||||
| 	# |  | ||||||
| 	# je_nejake_ostatni = any(filter(not_empty, hlavni_problemy_slovnik[-1].values())) > 0 |  | ||||||
| 
 |  | ||||||
| 	je_nejake_ostatni = len(hlavni_problemy) - len(temata_a_spol) > 0 |  | ||||||
| 
 |  | ||||||
| 	setrizeni_resitele_slovnik = {} |  | ||||||
| 	setrizeni_resitele = 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