Merge branch 'data_migrations' of gimli.ms.mff.cuni.cz:/akce/mam/git/mamweb into data_migrations
This commit is contained in:
commit
ad2a93117f
11 changed files with 226 additions and 57 deletions
|
@ -337,8 +337,8 @@
|
||||||
"sort_order": 33,
|
"sort_order": 33,
|
||||||
"title": "Výsledková listina",
|
"title": "Výsledková listina",
|
||||||
"tree": 1,
|
"tree": 1,
|
||||||
"url": "zadani/vysledkova-listina/",
|
"url": "seminar_aktualni_vysledky",
|
||||||
"urlaspattern": false
|
"urlaspattern": true
|
||||||
},
|
},
|
||||||
"model": "sitetree.treeitem",
|
"model": "sitetree.treeitem",
|
||||||
"pk": 16
|
"pk": 16
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
,anet,erebus,25.03.2020 22:21,file:///home/anet/.config/libreoffice/4;
|
|
|
@ -1,7 +1,8 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms import widgets
|
from django.forms import widgets, ModelForm
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
|
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
|
||||||
from reversion.admin import VersionAdmin
|
from reversion.admin import VersionAdmin
|
||||||
|
@ -12,11 +13,43 @@ from solo.admin import SingletonModelAdmin
|
||||||
# Todo: reversion
|
# Todo: reversion
|
||||||
|
|
||||||
import seminar.models as m
|
import seminar.models as m
|
||||||
|
import seminar.treelib as tl
|
||||||
|
|
||||||
admin.site.register(m.Skola)
|
admin.site.register(m.Skola)
|
||||||
admin.site.register(m.Prijemce)
|
admin.site.register(m.Prijemce)
|
||||||
admin.site.register(m.Rocnik)
|
admin.site.register(m.Rocnik)
|
||||||
admin.site.register(m.Cislo)
|
|
||||||
|
class CisloForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = m.Cislo
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
print("Cleaning...")
|
||||||
|
print(self.cleaned_data)
|
||||||
|
if self.cleaned_data.get('verejne_db') == False:
|
||||||
|
return self.cleaned_data
|
||||||
|
cn = m.CisloNode.objects.get(cislo=self.instance)
|
||||||
|
for ch in tl.all_children(cn):
|
||||||
|
if isinstance(ch, m.TemaVCisleNode):
|
||||||
|
if ch.tema.stav not in \
|
||||||
|
(m.Problem.STAV_ZADANY, m.Problem.STAV_VYRESENY):
|
||||||
|
raise ValidationError('Téma %(tema)s není zadané ani vyřešené', params={'tema':ch.tema})
|
||||||
|
|
||||||
|
if isinstance(ch, m.UlohaZadaniNode) or isinstance(ch, m.UlohaVzorakNode):
|
||||||
|
if ch.uloha.stav not in \
|
||||||
|
(m.Problem.STAV_ZADANY, m.Problem.STAV_VYRESENY):
|
||||||
|
raise ValidationError('Úloha %(uloha)s není zadaná ani vyřešená', params={'uloha':ch.uloha})
|
||||||
|
if isinstance(ch, m.ReseniNode):
|
||||||
|
for problem in ch.reseni.problem_set:
|
||||||
|
if problem not in \
|
||||||
|
(m.Problem.STAV_ZADANY, m.Problem.STAV_VYRESENY):
|
||||||
|
raise ValidationError('Problém %s není zadaný ani vyřešený', code=problem)
|
||||||
|
return self.cleaned_data
|
||||||
|
|
||||||
|
@admin.register(m.Cislo)
|
||||||
|
class CisloAdmin(admin.ModelAdmin):
|
||||||
|
form = CisloForm
|
||||||
|
|
||||||
@admin.register(m.Osoba)
|
@admin.register(m.Osoba)
|
||||||
class OsobaAdmin(admin.ModelAdmin):
|
class OsobaAdmin(admin.ModelAdmin):
|
||||||
|
|
|
@ -316,3 +316,85 @@ class JednoHodnoceniForm(forms.ModelForm):
|
||||||
OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm,
|
OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm,
|
||||||
extra = 0,
|
extra = 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# FIXME: Ideálně by mělo být součástí třídy níž, ale neumím to udělat
|
||||||
|
DATE_FORMAT = '%Y-%m-%d'
|
||||||
|
|
||||||
|
class OdevzdavatkoTabulkaFiltrForm(forms.Form):
|
||||||
|
"""Form pro filtrování přehledové odevzdávátkové tabulky
|
||||||
|
|
||||||
|
Inspirováno https://kam.mff.cuni.cz/mffzoom/"""
|
||||||
|
|
||||||
|
# Věci definované níž se importují i ve views pro odevzdávátko (Inspirováno https://docs.djangoproject.com/en/3.1/ref/models/fields/#field-choices)
|
||||||
|
|
||||||
|
RESITELE_RELEVANTNI = 'relevantni'
|
||||||
|
RESITELE_LETOSNI = 'letosni'
|
||||||
|
RESITELE_CHOICES = [
|
||||||
|
(RESITELE_RELEVANTNI, 'Relevantní řešitelé'), # I.e. nezobrazovat prázdné řádky tabulky
|
||||||
|
(RESITELE_LETOSNI, 'Všichni letošní'),
|
||||||
|
# Možná: všechny vč. historických?
|
||||||
|
]
|
||||||
|
|
||||||
|
PROBLEMY_MOJE = 'moje'
|
||||||
|
PROBLEMY_LETOSNI = 'letosni'
|
||||||
|
PROBLEMY_CHOICES = [
|
||||||
|
(PROBLEMY_MOJE, 'Moje problémy'), # Letošní problémy, které mají v sobě nebo v nadproblémech přiřazeného daného orga
|
||||||
|
(PROBLEMY_LETOSNI, 'Všechny letošní'),
|
||||||
|
# TODO: *hlavní problémy, možná všechny...
|
||||||
|
# XXX: Chtělo by to i "aktuálně zadané...
|
||||||
|
]
|
||||||
|
|
||||||
|
# TODO: Typy problémů (problémy, úlohy, ostatní, všechny)? Jen některá řešení (obodovaná/neobodovaná, víc řešitelů, ...)?
|
||||||
|
|
||||||
|
|
||||||
|
def gen_terminy():
|
||||||
|
import datetime
|
||||||
|
from time import strftime
|
||||||
|
|
||||||
|
from django.db.utils import OperationalError
|
||||||
|
try:
|
||||||
|
aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik
|
||||||
|
aktualni_cislo = m.Nastaveni.get_solo().aktualni_cislo
|
||||||
|
except OperationalError:
|
||||||
|
# django.db.utils.OperationalError: no such table: seminar_nastaveni
|
||||||
|
# Nemáme databázi, takže to selhalo. Pro jistotu vrátíme aspoň dvě možnosti, ať to nepadá dál
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.error("Rozbitá databáze (před počátečními migracemi?)")
|
||||||
|
return [('broken', 'Je to rozbitý'), ('fubar', 'Nefunguje to')]
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for cislo in m.Cislo.objects.filter(
|
||||||
|
rocnik=aktualni_rocnik,
|
||||||
|
poradi__lte=aktualni_cislo.poradi,
|
||||||
|
).reverse(): # Standardně se řadí od nejnovějšího čísla
|
||||||
|
# Předem je mi líto kohokoliv, kdo tyhle řádky bude číst...
|
||||||
|
if cislo.datum_vydani is not None and cislo.datum_vydani <= datetime.date.today():
|
||||||
|
result.append((
|
||||||
|
strftime(DATE_FORMAT, cislo.datum_vydani.timetuple()),
|
||||||
|
f"Vydání {cislo.poradi}. čísla"))
|
||||||
|
if cislo.datum_preddeadline is not None and cislo.datum_preddeadline <= datetime.date.today():
|
||||||
|
result.append((
|
||||||
|
strftime(DATE_FORMAT, cislo.datum_preddeadline.timetuple()),
|
||||||
|
f"Předdeadline {cislo.poradi}. čísla"))
|
||||||
|
if cislo.datum_deadline_soustredeni is not None and cislo.datum_deadline_soustredeni <= datetime.date.today():
|
||||||
|
result.append((
|
||||||
|
strftime(DATE_FORMAT, cislo.datum_deadline_soustredeni.timetuple()),
|
||||||
|
f"Sous. deadline {cislo.poradi}. čísla"))
|
||||||
|
if cislo.datum_deadline is not None and cislo.datum_deadline <= datetime.date.today():
|
||||||
|
result.append((
|
||||||
|
strftime(DATE_FORMAT, cislo.datum_deadline.timetuple()),
|
||||||
|
f"Finální deadline {cislo.poradi}. čísla"))
|
||||||
|
result.append((
|
||||||
|
strftime(DATE_FORMAT, datetime.date.today().timetuple()), f"Dnes"))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
# NOTE: Initial definuji pro jednotlivé fieldy, aby to bylo tady a nebylo potřeba to řešit ve views...
|
||||||
|
resitele = forms.ChoiceField(choices=RESITELE_CHOICES, initial=RESITELE_RELEVANTNI)
|
||||||
|
problemy = forms.ChoiceField(choices=PROBLEMY_CHOICES, initial=PROBLEMY_MOJE)
|
||||||
|
|
||||||
|
# choices jako parametr Select widgetu neumí brát callable, jen iterable, takže si pro jednoduchost můžu rovnou uložit výsledek sem...
|
||||||
|
terminy = gen_terminy()
|
||||||
|
reseni_od = forms.DateField(input_formats=[DATE_FORMAT], widget=forms.Select(choices=terminy), initial=terminy[-2])
|
||||||
|
reseni_do = forms.DateField(input_formats=[DATE_FORMAT], widget=forms.Select(choices=terminy), initial=terminy[-1])
|
||||||
|
|
|
@ -864,31 +864,31 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
return str(self.kod)
|
return str(self.kod)
|
||||||
return '<Není zadaný>'
|
return '<Není zadaný>'
|
||||||
|
|
||||||
def verejne(self):
|
# def verejne(self):
|
||||||
# aktuálně podle stavu problému
|
# # aktuálně podle stavu problému
|
||||||
# FIXME pro některé problémy možná chceme override
|
# # FIXME pro některé problémy možná chceme override
|
||||||
# FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
|
# # FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
|
||||||
# Je to tak správně? Podle aktuální představy ano.
|
# # Je to tak správně? Podle aktuální představy ano.
|
||||||
stav_verejny = False
|
# stav_verejny = False
|
||||||
if self.stav == 'zadany' or self.stav == 'vyreseny':
|
# if self.stav == 'zadany' or self.stav == 'vyreseny':
|
||||||
stav_verejny = True
|
# stav_verejny = True
|
||||||
print("stav_verejny: {}".format(stav_verejny))
|
# print("stav_verejny: {}".format(stav_verejny))
|
||||||
|
#
|
||||||
cislo_verejne = False
|
# cislo_verejne = False
|
||||||
cislonode = self.cislo_node()
|
# cislonode = self.cislo_node()
|
||||||
if cislonode is None:
|
# if cislonode is None:
|
||||||
# problém nemá vlastní node, veřejnost posuzujeme jen podle stavu
|
# # problém nemá vlastní node, veřejnost posuzujeme jen podle stavu
|
||||||
print("empty node")
|
# print("empty node")
|
||||||
return stav_verejny
|
# return stav_verejny
|
||||||
else:
|
# else:
|
||||||
cislo_zadani = cislonode.cislo
|
# cislo_zadani = cislonode.cislo
|
||||||
if (cislo_zadani and cislo_zadani.verejne()):
|
# if (cislo_zadani and cislo_zadani.verejne()):
|
||||||
print("cislo: {}".format(cislo_zadani))
|
# print("cislo: {}".format(cislo_zadani))
|
||||||
cislo_verejne = True
|
# cislo_verejne = True
|
||||||
print("stav_verejny: {}".format(stav_verejny))
|
# print("stav_verejny: {}".format(stav_verejny))
|
||||||
print("cislo_verejne: {}".format(cislo_verejne))
|
# print("cislo_verejne: {}".format(cislo_verejne))
|
||||||
return (stav_verejny and cislo_verejne)
|
# return (stav_verejny and cislo_verejne)
|
||||||
verejne.boolean = True
|
# verejne.boolean = True
|
||||||
|
|
||||||
def verejne_url(self):
|
def verejne_url(self):
|
||||||
return reverse('seminar_problem', kwargs={'pk': self.id})
|
return reverse('seminar_problem', kwargs={'pk': self.id})
|
||||||
|
@ -962,6 +962,7 @@ class Clanek(Problem):
|
||||||
cislo = models.ForeignKey(Cislo, blank=True, null=True, on_delete=models.PROTECT,
|
cislo = models.ForeignKey(Cislo, blank=True, null=True, on_delete=models.PROTECT,
|
||||||
verbose_name='číslo vydání', related_name='vydane_clanky')
|
verbose_name='číslo vydání', related_name='vydane_clanky')
|
||||||
|
|
||||||
|
@cached_property
|
||||||
def kod_v_rocniku(self):
|
def kod_v_rocniku(self):
|
||||||
if self.stav == 'zadany':
|
if self.stav == 'zadany':
|
||||||
# Nemělo by být potřeba
|
# Nemělo by být potřeba
|
||||||
|
|
|
@ -4,6 +4,14 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
<form method=get action=.>
|
||||||
|
{{ filtr.resitele }}
|
||||||
|
{{ filtr.problemy }}
|
||||||
|
Od: {{ filtr.reseni_od }}
|
||||||
|
Do: {{ filtr.reseni_do }}
|
||||||
|
<input type=submit value="→">
|
||||||
|
</form>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td> {# Prázdná buňka v levém horním rohu #}
|
<td></td> {# Prázdná buňka v levém horním rohu #}
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
<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>
|
||||||
{% with vysledkovka_s_neverejnymi as radky_vysledkovky %}
|
{% with vysledkovka_s_neverejnymi as radky_vysledkovky %}
|
||||||
|
{% with cisla_s_neverejnymi as cisla %}
|
||||||
{% include "seminar/vysledkovka_rocnik.html" %}
|
{% include "seminar/vysledkovka_rocnik.html" %}
|
||||||
|
{% endwith %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -230,9 +230,9 @@ def cisla_rocniku(rocnik, jen_verejne=True):
|
||||||
seznam objektů typu Cislo
|
seznam objektů typu Cislo
|
||||||
"""
|
"""
|
||||||
if jen_verejne:
|
if jen_verejne:
|
||||||
return rocnik.verejna_cisla()
|
return rocnik.verejne_vysledkovky_cisla()
|
||||||
else:
|
else:
|
||||||
return rocnik.cisla.all()
|
return rocnik.cisla.all().order_by('poradi')
|
||||||
|
|
||||||
def hlavni_problem(problem):
|
def hlavni_problem(problem):
|
||||||
""" Pro daný problém vrátí jeho nejvyšší nadproblém."""
|
""" Pro daný problém vrátí jeho nejvyšší nadproblém."""
|
||||||
|
|
|
@ -12,6 +12,7 @@ import logging
|
||||||
|
|
||||||
import seminar.models as m
|
import seminar.models as m
|
||||||
import seminar.forms as f
|
import seminar.forms as f
|
||||||
|
from seminar.forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm
|
||||||
from seminar.utils import aktivniResitele, resi_v_rocniku
|
from seminar.utils import aktivniResitele, resi_v_rocniku
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -41,28 +42,55 @@ class TabulkaOdevzdanychReseniView(ListView):
|
||||||
|
|
||||||
def inicializuj_osy_tabulky(self):
|
def inicializuj_osy_tabulky(self):
|
||||||
"""Vyrobí prvotní querysety pro sloupce a řádky, tj. seznam všech řešitelů a problémů"""
|
"""Vyrobí prvotní querysety pro sloupce a řádky, tj. seznam všech řešitelů a problémů"""
|
||||||
|
# FIXME: jméno metody není vypovídající...
|
||||||
# NOTE: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistují ty objekty (?). TODO: Otestovat
|
# NOTE: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistují ty objekty (?). TODO: Otestovat
|
||||||
# TODO: Prefetches, Select related, ...
|
# TODO: Prefetches, Select related, ...
|
||||||
self.resitele = m.Resitel.objects.all()
|
self.resitele = m.Resitel.objects.all()
|
||||||
self.problemy = m.Problem.objects.all()
|
self.problemy = m.Problem.objects.all()
|
||||||
|
self.reseni = m.Reseni.objects.all()
|
||||||
|
|
||||||
|
form = FiltrForm(self.request.GET)
|
||||||
|
if form.is_valid():
|
||||||
|
fcd = form.cleaned_data
|
||||||
|
resitele = fcd["resitele"]
|
||||||
|
problemy = fcd["problemy"]
|
||||||
|
reseni_od = fcd["reseni_od"]
|
||||||
|
reseni_do = fcd["reseni_do"]
|
||||||
|
else:
|
||||||
|
resitele = FiltrForm.get_initial_for_field(FormFiltr.resitele, "resitele")
|
||||||
|
problemy = FiltrForm.get_initial_for_field(FormFiltr.problemy, "problemy")
|
||||||
|
resitele_od = FiltrForm.get_initial_for_field(FormFiltr.resitele_od, "resitele_od")
|
||||||
|
resitele_do = FiltrForm.get_initial_for_field(FormFiltr.resitele_do, "resitele_do")
|
||||||
|
|
||||||
|
|
||||||
|
# Filtrujeme!
|
||||||
|
aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci
|
||||||
|
if resitele == FiltrForm.RESITELE_RELEVANTNI:
|
||||||
|
logger.warning("Někdo chtěl v tabulce jen relevantní řešitele a měl smůlu :-(")
|
||||||
|
resitele = FiltrForm.RESITELE_LETOSNI # Fall-through
|
||||||
|
elif resitele == FiltrForm.RESITELE_LETOSNI:
|
||||||
|
self.resitele = resi_v_rocniku(aktualni_rocnik)
|
||||||
|
|
||||||
|
if problemy == FiltrForm.PROBLEMY_MOJE:
|
||||||
|
org = m.Organizator.objects.get(osoba__user=self.request.user)
|
||||||
|
from django.db.models import Q
|
||||||
|
self.problemy = self.problemy.filter(Q(autor=org)|Q(garant=org)|Q(opravovatele=org), stav=m.Problem.STAV_ZADANY)
|
||||||
|
elif problemy == FiltrForm.PROBLEMY_LETOSNI:
|
||||||
|
self.problemy = self.problemy.filter(stav=m.Problem.STAV_ZADANY)
|
||||||
|
#self.problemy = list(filter(lambda problem: problem.rocnik() == aktualni_rocnik, self.problemy)) # DB HOG? # FIXME: některé problémy nemají ročník....
|
||||||
|
# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy.
|
||||||
|
self.problemy = self.problemy.non_polymorphic()
|
||||||
|
|
||||||
|
self.reseni = self.reseni.filter(cas_doruceni__date__gte=reseni_od, cas_doruceni__date__lte=reseni_do)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.inicializuj_osy_tabulky()
|
self.inicializuj_osy_tabulky()
|
||||||
self.akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi...
|
|
||||||
self.resitele = resi_v_rocniku(self.akt_rocnik)
|
|
||||||
# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy.
|
|
||||||
self.problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic()
|
|
||||||
|
|
||||||
qs = super().get_queryset()
|
qs = super().get_queryset()
|
||||||
qs = qs.filter(problem__in=self.problemy).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba')
|
qs = qs.filter(problem__in=self.problemy, reseni__in=self.reseni, reseni__resitele__in=self.resitele).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba')
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_context_data(self, *args, **kwargs):
|
||||||
# FIXME: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistuje Nastavení.
|
# self.resitele, self.reseni a self.problemy jsou již nastavené
|
||||||
self.akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi...
|
|
||||||
self.resitele = resi_v_rocniku(self.akt_rocnik)
|
|
||||||
# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy.
|
|
||||||
self.problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic()
|
|
||||||
|
|
||||||
ctx = super().get_context_data(*args, **kwargs)
|
ctx = super().get_context_data(*args, **kwargs)
|
||||||
ctx['problemy'] = self.problemy
|
ctx['problemy'] = self.problemy
|
||||||
|
@ -100,6 +128,10 @@ class TabulkaOdevzdanychReseniView(ListView):
|
||||||
hodnoty.append(resiteluv_radek)
|
hodnoty.append(resiteluv_radek)
|
||||||
ctx['radky'] = list(zip(self.resitele, hodnoty))
|
ctx['radky'] = list(zip(self.resitele, hodnoty))
|
||||||
|
|
||||||
|
ctx['filtr'] = FiltrForm(initial=self.request.GET)
|
||||||
|
# Pro použití hacku na automatické {{form.media}} v template:
|
||||||
|
ctx['form'] = ctx['filtr']
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
# Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji?
|
# Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji?
|
||||||
|
|
|
@ -29,7 +29,7 @@ from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm
|
||||||
import seminar.forms as f
|
import seminar.forms as f
|
||||||
import seminar.templatetags.treenodes as tnltt
|
import seminar.templatetags.treenodes as tnltt
|
||||||
import seminar.views.views_rest as vr
|
import seminar.views.views_rest as vr
|
||||||
from seminar.views.vysledkovka import vysledkovka_rocniku, vysledkovka_cisla
|
from seminar.views.vysledkovka import vysledkovka_rocniku, vysledkovka_cisla, body_resitelu
|
||||||
|
|
||||||
from datetime import timedelta, date, datetime, MAXYEAR
|
from datetime import timedelta, date, datetime, MAXYEAR
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -185,7 +185,7 @@ class TNLData(object):
|
||||||
return [cls.from_treenode(treenode)]
|
return [cls.from_treenode(treenode)]
|
||||||
else:
|
else:
|
||||||
found = []
|
found = []
|
||||||
for tn in all_children(treenode):
|
for tn in treelib.all_children(treenode):
|
||||||
result = cls.filter_treenode(tn, predicate)
|
result = cls.filter_treenode(tn, predicate)
|
||||||
# Result by v tuhle chvíli měl být seznam TNLDat odpovídající treenodům, jež matchnuly predikát.
|
# Result by v tuhle chvíli měl být seznam TNLDat odpovídající treenodům, jež matchnuly predikát.
|
||||||
for tnl in result:
|
for tnl in result:
|
||||||
|
@ -503,6 +503,7 @@ def ZadaniAktualniVysledkovkaView(request):
|
||||||
pass
|
pass
|
||||||
# vysledkovka s neverejnyma vysledkama
|
# vysledkovka s neverejnyma vysledkama
|
||||||
vysledkovka_s_neverejnymi = vysledkovka_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False)
|
vysledkovka_s_neverejnymi = vysledkovka_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False)
|
||||||
|
cisla_s_neverejnymi = cisla_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'seminar/zadani/AktualniVysledkovka.html',
|
'seminar/zadani/AktualniVysledkovka.html',
|
||||||
|
@ -511,6 +512,7 @@ def ZadaniAktualniVysledkovkaView(request):
|
||||||
'radky_vysledkovky': vysledkovka,
|
'radky_vysledkovky': vysledkovka,
|
||||||
'cisla': cisla,
|
'cisla': cisla,
|
||||||
'vysledkovka_s_neverejnymi': vysledkovka_s_neverejnymi,
|
'vysledkovka_s_neverejnymi': vysledkovka_s_neverejnymi,
|
||||||
|
'cisla_s_neverejnymi': cisla_s_neverejnymi,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ def sloupec_s_poradim(setrizene_body):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def body_resitelu(resitele, za, odjakziva=True):
|
def body_resitelu(resitele, za, odjakziva=True, jen_verejne=False):
|
||||||
""" Funkce počítající počty bodů pro zadané řešitele,
|
""" 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.
|
buď odjakživa do daného ročníku/čísla anebo za daný ročník/číslo.
|
||||||
Parametry:
|
Parametry:
|
||||||
|
@ -94,12 +94,22 @@ def body_resitelu(resitele, za, odjakziva=True):
|
||||||
body_k_zapocteni = Sum('reseni__hodnoceni__body',
|
body_k_zapocteni = Sum('reseni__hodnoceni__body',
|
||||||
filter=( Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok=rok,
|
filter=( Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok=rok,
|
||||||
reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi) ))
|
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ě.
|
elif rocnik and odjakziva: # Spočítáme body za starší ročníky až do zadaného včetně.
|
||||||
body_k_zapocteni = Sum('reseni__hodnoceni__body',
|
if jen_verejne:
|
||||||
filter= Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte=rok))
|
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.
|
elif rocnik and not odjakziva: # Spočítáme body za daný ročník.
|
||||||
body_k_zapocteni = Sum('reseni__hodnoceni__body',
|
if jen_verejne:
|
||||||
filter= Q(reseni__hodnoceni__cislo_body__rocnik=rocnik))
|
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:
|
else:
|
||||||
assert True, "body_resitelu: Neplatná kombinace za a odjakživa."
|
assert True, "body_resitelu: Neplatná kombinace za a odjakživa."
|
||||||
|
|
||||||
|
@ -149,14 +159,14 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
|
||||||
body_cisla_slov[cislo.id] = cislobody
|
body_cisla_slov[cislo.id] = cislobody
|
||||||
|
|
||||||
# získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně
|
# 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)
|
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žší
|
# 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)
|
setrizeni_resitele_id, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn)
|
||||||
poradi = sloupec_s_poradim(setrizene_body)
|
poradi = sloupec_s_poradim(setrizene_body)
|
||||||
|
|
||||||
# získáme body odjakživa
|
# získáme body odjakživa
|
||||||
resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, rocnik)
|
resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, rocnik, jen_verejne=jen_verejne)
|
||||||
|
|
||||||
# vytvoříme jednotlivé sloupce výsledkovky
|
# vytvoříme jednotlivé sloupce výsledkovky
|
||||||
radky_vysledkovky = []
|
radky_vysledkovky = []
|
||||||
|
@ -216,7 +226,7 @@ def pricti_body(slovnik, resitel, body):
|
||||||
|
|
||||||
slovnik[resitel.id] += body
|
slovnik[resitel.id] += body
|
||||||
|
|
||||||
def secti_body_za_rocnik(za, aktivni_resitele):
|
def secti_body_za_rocnik(za, aktivni_resitele, jen_verejne):
|
||||||
""" Spočítá body za ročník (celý nebo do daného čísla),
|
""" Spočítá body za ročník (celý nebo do daného čísla),
|
||||||
setřídí je sestupně a vrátí jako seznam.
|
setřídí je sestupně a vrátí jako seznam.
|
||||||
Parametry:
|
Parametry:
|
||||||
|
@ -224,7 +234,7 @@ def secti_body_za_rocnik(za, aktivni_resitele):
|
||||||
daného čísla
|
daného čísla
|
||||||
"""
|
"""
|
||||||
# spočítáme všem řešitelům jejich body za ročník (False => ne odjakživa)
|
# 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)
|
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ě
|
# zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně
|
||||||
resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(),
|
resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(),
|
||||||
key = lambda x: x[1], reverse = True)
|
key = lambda x: x[1], reverse = True)
|
||||||
|
@ -380,10 +390,10 @@ def vysledkovka_cisla(cislo, context=None):
|
||||||
hlavni_problemy_slovnik, cislobody = secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy)
|
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ě
|
# 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)
|
resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo, aktivni_resitele, jen_verejne=True)
|
||||||
|
|
||||||
# získáme body odjakživa
|
# získáme body odjakživa
|
||||||
resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo)
|
resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo, jen_verejne=True)
|
||||||
|
|
||||||
# řešitelé setřídění podle bodů za číslo sestupně
|
# řešitelé setřídění podle bodů za číslo sestupně
|
||||||
setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn]
|
setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn]
|
||||||
|
|
Loading…
Reference in a new issue