diff --git a/Schema_new.dia b/Schema_new.dia index f09c0589..c212ec3b 100644 Binary files a/Schema_new.dia and b/Schema_new.dia differ diff --git a/galerie/models.py b/galerie/models.py index c6acc5df..2d9b8e56 100644 --- a/galerie/models.py +++ b/galerie/models.py @@ -69,6 +69,8 @@ class Obrazek(models.Model): ordering = ['nazev'] def obrazek_maly_tag(self): + if not self.obrazek_maly: + return '' return u''.format(self.obrazek_maly.url) obrazek_maly_tag.short_description = "Náhled" obrazek_maly_tag.allow_tags = True diff --git a/mamweb/static/css/mamweb.css b/mamweb/static/css/mamweb.css index 357b5027..7e7adbfd 100644 --- a/mamweb/static/css/mamweb.css +++ b/mamweb/static/css/mamweb.css @@ -14,8 +14,31 @@ div.container { margin: auto; } +.org-logged-in div.container { + margin-top: 20px; +} + div.login-bar { background: #6a0043; + color: #f9d59e; + width: 100%; + + position: fixed; + margin-top: -20px; + min-height: 20px; + z-index: 20; + + padding-left: 5px; + padding-right: 5px; +} + +div.login-bar div { + display: inline; +} + +a.login-ref-admin { + display: inline; + color: #fffbf6; } /* odkazy a nadpisy */ @@ -74,16 +97,16 @@ h6 { .org-logged-in .mam-text-plugin { - border: dashed 1px #f77; + border: dashed 1px #6a0043; padding: 5px; margin: -5px; } .mam-org-only { - background: #fff0d7; + background: #eee4ec; padding: 10px; margin: 10px -10px; - border: orange 2px dashed; + border: #6a0043 2px dashed; } .mam-org-only .mam-org-only { @@ -123,6 +146,8 @@ h1 { margin-top: 0px; } + + /* Comments */ #id_comment { @@ -191,7 +216,7 @@ vikendovka #header.NOCsoustredeni { background-image: url("../images/header/vylet.jpg");} #header.NOCzadani { background-image: url("../images/header/stiny.jpg");} #header.NOCclanky { background-image: url("../images/header/ohen.jpg");} -#header.NOCarchiv { background-image: url("../images/header/vikendovka.jpg");} +#header.NOCarchiv { background-image: url("../images/header/stiny.jpg");} #header img.logo { @@ -407,6 +432,10 @@ ul.submenu { /* malý tablet, mobil */ @media (max-width: 650px) { + #hide-if-small.login-bar-flatpage { + display: none; + } + #title { display: none; } @@ -558,7 +587,7 @@ div.seznam_orgu { text-align: center; } -div.org_pole { +div.org_pole, div.rocnik_pole { display: inline-block; width: 30%; min-width: 300px; @@ -576,16 +605,24 @@ div.org_email { font-weight: bold; } -/*otáčecí karty organizátorů*/ +/*otáčecí karty (orgové, archiv) */ .flip-card { - width: 200px; - height: 250px; perspective: 1000px; /* Remove this if you don't want the 3D effect */ margin-left: auto; margin-right: auto; } +#organizatori.flip-card { + width: 200px; + height: 250px; +} + +#archiv.flip-card { + width: 210px; + height: 298px; +} + /* This container is needed to position the front and back side */ .flip-card-inner { position: relative; @@ -614,9 +651,10 @@ div.org_email { background-color: #bbb; } -div.foto_org img { +div.flip-card-foto img { width: 100%; height: 100%; + filter: drop-shadow(0px 3px 3px rgba(0, 0, 0, 0.4)); /* FIXME: obecně k obrázkům */ } /* Style the back side */ @@ -631,6 +669,23 @@ div.foto_org img { padding-top: 20px; } +/* karty archiv */ + +div.popis_rocniku { + text-align: left; + font-weight: bold; + margin: 20px; +} + + +div.popis_rocniku a{ + color: black; +} + +div.popis_rocniku a:hover{ + color: #6f2509; +} + /* graf na úvodní stránce */ a span.popup { diff --git a/mamweb/templates/base.html b/mamweb/templates/base.html index a53fa3df..a7616627 100644 --- a/mamweb/templates/base.html +++ b/mamweb/templates/base.html @@ -36,21 +36,21 @@ -
- - {% if user.is_staff %} -
- {% if view.object %} - Objekt {{ view.object }}: {{ view.object }} - {% if view.object.admin_url %}[admin]{% endif %} - {% endif %} - {% if flatpage %} - Stránka {{ flatpage.url }} ({{ flatpage.title }}) - [admin] - {% endif %} -
- {% endif %} + {% if user.is_staff %} +
+ {% if view.object %} + Objekt {{ view.object }}: {{ view.object }} + {% if view.object.admin_url %}{% endif %} + {% endif %} + {% if flatpage %} + + + {% endif %} + +
+ {% endif %} +
diff --git a/seminar/migrations/0081_auto_20200408_2221.py b/seminar/migrations/0081_auto_20200408_2221.py new file mode 100644 index 00000000..6cf908bb --- /dev/null +++ b/seminar/migrations/0081_auto_20200408_2221.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.9 on 2020-04-08 20:21 + +from django.db import migrations, models +import seminar.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0080_zruseni_claneknode_a_konferanode'), + ] + + operations = [ + migrations.AddField( + model_name='cislo', + name='titulka_nahled', + field=models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to='', verbose_name='Obrázek titulní strany'), + ), + migrations.AlterField( + model_name='cislo', + name='pdf', + field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, upload_to=seminar.models.cislo_pdf_filename, verbose_name='pdf'), + ), + ] diff --git a/seminar/models.py b/seminar/models.py index c22ab5d3..226fec78 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- import os import random +import subprocess +import pathlib +import tempfile from django.db import models from django.contrib import auth @@ -27,6 +30,7 @@ from unidecode import unidecode # Používám pro získání ID odkazu (ještě from polymorphic.models import PolymorphicModel + class SeminarModelBase(models.Model): class Meta: @@ -407,7 +411,11 @@ class Rocnik(SeminarModelBase): def cislo_pdf_filename(self, filename): rocnik = str(self.rocnik.rocnik) - return os.path.join('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.poradi)) + return pathlib.Path('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.poradi)) + +def cislo_png_filename(self, filename): + rocnik = str(self.rocnik.rocnik) + return pathlib.Path('cislo', 'png', rocnik, '{}-{}.png'.format(rocnik, self.poradi)) @reversion.register(ignore_duplicates=True) class Cislo(SeminarModelBase): @@ -451,7 +459,10 @@ class Cislo(SeminarModelBase): help_text='Neveřejná poznámka k číslu (plain text)') pdf = models.FileField('pdf', upload_to=cislo_pdf_filename, null=True, blank=True, - help_text='Pdf čísla, které si mohou řešitelé stáhnout') + help_text='PDF čísla, které si mohou řešitelé stáhnout') + + titulka_nahled = models.ImageField('Obrázek titulní strany', upload_to=cislo_png_filename, null=True, blank=True, + help_text='Obrázek titulní strany, generuje se automaticky') # má OneToOneField s: # CisloNode @@ -488,6 +499,35 @@ class Cislo(SeminarModelBase): return None return cs[i] + def vygeneruj_nahled(self): + VYSKA = 594 + sirka = int(VYSKA*210/297) + if not self.pdf: + return + + + # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej + if not self.titulka_nahled or os.path.getmtime(self.titulka_nahled.path) < os.path.getmtime(self.pdf.path): + png_filename = pathlib.Path(tempfile.mkdtemp(), 'nahled.png') + + subprocess.call([ + "convert", + "-density", "300x300", + "-geometry", "{}x{}".format(VYSKA, sirka), + "-background", "white", + "-flatten", + "{}[0]".format(self.pdf.path), # titulní strana + png_filename + ]) + + with open(png_filename,'rb') as f: + self.titulka_nahled.save('',f,True) + + png_filename.unlink() + png_filename.parent.rmdir() + + + @classmethod def get(cls, rocnik, cislo): try: @@ -499,6 +539,7 @@ class Cislo(SeminarModelBase): def save(self, *args, **kwargs): super().save(*args, **kwargs) + self.vygeneruj_nahled() # *Node.save() aktualizuje název *Nodu. try: self.cislonode.save() diff --git a/seminar/templates/seminar/archiv/cisla.html b/seminar/templates/seminar/archiv/cisla.html index fbb19263..3c4a38b4 100644 --- a/seminar/templates/seminar/archiv/cisla.html +++ b/seminar/templates/seminar/archiv/cisla.html @@ -8,18 +8,56 @@ {% endblock %}{% endblock %} -
+ + + {% for rocnik, url_png in object_list.items %} + +
+ +

+ Ročník {{ rocnik }} +

+ + + {# karta ročníku - zepředu obrázek prvního čísla, zezadu odkaz na jednotlivá čísla a výsledkovku #} + +
+ +
+
+ +
+ {{ rocnik }} +
+ +
+
+
+ Jednotlivá čísla: +
    + {% for cislo in rocnik.cisla.all reversed %} +
  • {{ cislo.poradi }}. číslo {% if cislo.pdf %}(pdf) {% endif %} + {% empty %} + --- + {% endfor %} +
+ Výsledková listina +
+ +
+
+
+ + {# konec karty ročníku #} + +
+
-
    - {% for r in object_list %} -
  • Ročník {{ r }} {% empty %} Nejsou žádné ročníky {% endfor %} -
{% endblock content %} - diff --git a/seminar/templates/seminar/archiv/cislo.html b/seminar/templates/seminar/archiv/cislo.html index 955988f1..80905e00 100644 --- a/seminar/templates/seminar/archiv/cislo.html +++ b/seminar/templates/seminar/archiv/cislo.html @@ -46,15 +46,15 @@
  • Obálkování
  • - {% endif %} + {% endif %} {% if cislo.verejna_vysledkovka %} -

    Výsledkovka ({% now "jS F Y H:i" %})

    +

    Výsledkovka

    {% else %} {% if user.is_staff %}
    -

    Výsledkovka (neveřejná, {% now "jS F Y H:i:s" %})

    +

    Výsledkovka (neveřejná)

    {% endif %} {% endif %} @@ -73,7 +73,7 @@ {% autoescape off %}{{ rv.poradi }}{% endautoescape %} - {% if rv.titul is not '' %} + {% if rv.titul %} {{ rv.titul }}MM {% endif %} {{ rv.resitel.osoba.plne_jmeno }} @@ -86,14 +86,11 @@ {% endfor %} - {% endif %} + {% endif %} {% if not cislo.verejna_vysledkovka and user.is_staff %}
    {% endif %} - Čas: {% now "jS F Y H:i:s" %} -
    {% endblock content %} - diff --git a/seminar/templates/seminar/archiv/rocnik.html b/seminar/templates/seminar/archiv/rocnik.html index 64c4029d..2dd99ab4 100644 --- a/seminar/templates/seminar/archiv/rocnik.html +++ b/seminar/templates/seminar/archiv/rocnik.html @@ -2,13 +2,20 @@ {% block content %}
    -

    +

    {% block nadpis1a %}{% block nadpis1b %} - Ročník {{ rocnik.roman }} + Ročník {{ rocnik }} {% endblock %}{% endblock %} -

    + -

    Ročník číslo {{ rocnik.rocnik }} ({{ rocnik.prvni_rok }}/{{ rocnik.druhy_rok }}) + {% if temata_v_rocniku %} +

    Témata

    + + {% endif %}
      {% for c in rocnik.verejna_cisla %} @@ -19,15 +26,6 @@ {% endfor %}
    - {% if temata_v_rocniku %} -

    Témata

    - - {% endif %} - {% if vysledkovka %} {% if user.is_staff %}
    @@ -42,7 +40,7 @@ {% if user.is_staff and vysledkovka_s_neverejnymi %}

    Výsledková listina včetně neveřejných bodů

    - {% with vysledkovka_s_neverejnymi as vysledkovka %} + {% with radky_vyledkovky_s_neverejnymi as radky_vysledkovky %} {% include "seminar/vysledkovka_rocnik.html" %} {% endwith %}
    @@ -50,7 +48,3 @@
    {% endblock content %} - - - - diff --git a/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex b/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex index 75d8eb79..4218de57 100644 --- a/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex +++ b/seminar/templates/seminar/archiv/rocnik_vysledkovka.tex @@ -7,7 +7,7 @@ \endhead \hline \endfoot -{% for rv in vysledkovka.radky %}{{ rv.poradi }} & {% if rv.titul %}\titul{{ lb }}{{ rv.titul }}}~{% endif %}{{ rv.resitel.jmeno|slice:":1" }}.~{{ rv.resitel.prijmeni }} & {% if rv.resitel.rocnik %}{{ rv.resitel.rocnik }}.{% endif %} & {{ rv.body_odjakziva }} {% for b in rv.body_cisla %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\ +{% 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.resitel.rocnik %}{{ rv.resitel.rocnik }}.{% endif %} & {{ rv.body_odjakziva }} {% for b in rv.body_cisla_sezn %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\ {% endfor %}\end{longtable} {% endwith %} {% endwith %} diff --git a/seminar/templates/seminar/cojemam/organizatori.html b/seminar/templates/seminar/cojemam/organizatori.html index 8e8f1aaa..a3957101 100644 --- a/seminar/templates/seminar/cojemam/organizatori.html +++ b/seminar/templates/seminar/cojemam/organizatori.html @@ -46,12 +46,12 @@ {# karta organizátora - zepředu fotka, zezadu popis, u neaktivních data kdy organizovali #} -
    +
    -
    +
    {% if org.osoba.foto %} {{org.osoba.jmeno}} {{org.osoba.prijmeni}} {% else %} {# pokud osoba nemá fotku, zobrazuje se defaultní obrázek #} diff --git a/seminar/templates/seminar/vysledkovka_rocnik.html b/seminar/templates/seminar/vysledkovka_rocnik.html index f1dc1d79..424f805b 100644 --- a/seminar/templates/seminar/vysledkovka_rocnik.html +++ b/seminar/templates/seminar/vysledkovka_rocnik.html @@ -4,23 +4,23 @@ Jméno R. Odjakživa - {% for c in vysledkovka.cisla %} + {% for c in cisla %} - {{c.rocnik.rocnik}}.{{ c.cislo }} + {{c.rocnik.rocnik}}.{{ c.poradi }} {% endfor %} Celkem -{% for rv in vysledkovka.radky %} +{% for rv in radky_vysledkovky %} {% autoescape off %}{{ rv.poradi }}{% endautoescape %} {% if rv.titul %} {{ rv.titul }}MM {% endif %} - {{ rv.resitel.plne_jmeno }} + {{ rv.resitel.osoba.plne_jmeno }} {{ rv.resitel.rocnik }} - {{ rv.body_odjakziva }} - {% for b in rv.body_cisla %} + {{ rv.body_celkem_odjakziva }} + {% for b in rv.body_cisla_sezn %} {{ b }} {% endfor %} {{ rv.body_rocnik }} diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 01546843..e72f23aa 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -308,93 +308,152 @@ class ArchivView(generic.ListView): def get_context_data(self, **kwargs): context = super(ArchivView, self).get_context_data(**kwargs) - vyska = 297 # px - sirka = 210 # px + vyska = 594 # px + sirka = 420 # px - # nejnovějších 10 zveřejněných čísel - # cisla = Cislo.objects.filter(verejne_db=True)[:10] - cisla = Cislo.objects.filter(poradi=1)[:10] + # první číslo z každého ročníku + cisla = Cislo.objects.filter(poradi=1) # op == os.path, udělá z argumentů cestu png_dir = op.join(settings.MEDIA_ROOT, "cislo", "png") - # seznam [(url obrázku, číslo)] - urls = [] - - for i, c in enumerate(cisla): - if not c.pdf: - continue - filename = os.path.split(c.pdf.file.name)[1].split(".")[0] - png_filename = "{}-{}px.png".format(filename, vyska) - - # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej - png_path = op.join(png_dir, png_filename) - if not op.exists(png_path) or \ - op.getmtime(png_path) < op.getmtime(c.pdf.path): - - subprocess.call([ - "convert", - "-density", "300x300", - "-geometry", "{}x{}".format(vyska, sirka), - "-background", "white", - "-flatten", - "-rotate", str(90 * i), - "{}[0]".format(c.pdf.path), # titulní strana - png_path - ]) - - urls.append( - (op.join(settings.MEDIA_URL, "cislo", "png", png_filename), c) - ) - vyska, sirka = sirka, vyska / 2 - - tags = [] - - def spirala(urls, tags, idx): - """Rekurzivně prochází urls a generuje strom elementů do tags""" - if idx >= len(urls): - return - - img_url, cislo = urls[idx] - tags.append( - "
    " - .format( - 50 if idx % 4 == 2 else 0, - 50 if idx % 4 == 1 else 0, - 50 if idx % 2 == 1 else 100, - 50 if idx > 0 and idx % 2 == 0 else 100 - ) - ) - tags.append("".format( - cislo.verejne_url(), cislo.kod() - )) - tags.append( - "" - .format( - img_url, - 50 if idx % 4 == 3 else 0, - 50 if idx % 4 == 2 else 0, - 50 if idx % 2 == 0 else 100, - 50 if idx % 2 == 1 else 100 - ) - ) - tags.append("") - spirala(urls, tags, idx + 1) - tags.append("
    ") - spirala(urls, tags, 0) - - context["nahledy"] = "\n".join(tags) + # slovník {(ročník, url obrázku)} + urls ={} + + # for j, rocnik in enumerate(Rocnik.objects.all()): + # urls_rocnik = {} + # for i,c in enumerate(rocnik.cisla.all()): + # if not c.pdf: + # urls_rocnik[c.poradi] = op.join(settings.MEDIA_URL, "cislo", "png", "default.png") + # else: + # filename = os.path.split(c.pdf.file.name)[1].split(".")[0] + # png_filename = "{}.png".format(filename) + + # # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej + # png_path = op.join(png_dir, png_filename) + # if not op.exists(png_path) or \ + # op.getmtime(png_path) < op.getmtime(c.pdf.path): + + # subprocess.call([ + # "convert", + # "-density", "300x300", + # "-geometry", "{}x{}".format(vyska, sirka), + # "-background", "white", + # "-flatten", + # "{}[0]".format(c.pdf.path), # titulní strana + # png_path + # ]) + + # urls_rocnik[c.poradi] = op.join(settings.MEDIA_URL, "cislo", "png", png_filename) + # urls[rocnik] = urls_rocnik + + for i,c in enumerate(cisla): + if not c.pdf: + urls[c.rocnik] = op.join(settings.MEDIA_URL, "cislo", "png", "default.png") + else: + filename = os.path.split(c.pdf.file.name)[1].split(".")[0] + png_filename = "{}.png".format(filename) + + # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej + png_path = op.join(png_dir, png_filename) + if not op.exists(png_path) or \ + op.getmtime(png_path) < op.getmtime(c.pdf.path): + + subprocess.call([ + "convert", + "-density", "300x300", + "-geometry", "{}x{}".format(vyska, sirka), + "-background", "white", + "-flatten", + "{}[0]".format(c.pdf.path), # titulní strana + png_path + ]) + + urls[c.rocnik] = op.join(settings.MEDIA_URL, "cislo", "png", png_filename) + + context["object_list"] = urls + + print(context) + + # for i, c in enumerate(cisla): + # if not c.pdf: + # continue + # filename = os.path.split(c.pdf.file.name)[1].split(".")[0] + # png_filename = "{}-{}px.png".format(filename, vyska) + + # # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej + # png_path = op.join(png_dir, png_filename) + # if not op.exists(png_path) or \ + # op.getmtime(png_path) < op.getmtime(c.pdf.path): + + # subprocess.call([ + # "convert", + # "-density", "300x300", + # "-geometry", "{}x{}".format(vyska, sirka), + # "-background", "white", + # "-flatten", + # "-rotate", str(90 * i), + # "{}[0]".format(c.pdf.path), # titulní strana + # png_path + # ]) + + # urls.append( + # (op.join(settings.MEDIA_URL, "cislo", "png", png_filename), c) + # ) + # vyska, sirka = sirka, vyska / 2 + + # tags = [] + + # def spirala(urls, tags, idx): + # """Rekurzivně prochází urls a generuje strom elementů do tags""" + # if idx >= len(urls): + # return + + # img_url, cislo = urls[idx] + # tags.append( + # "
    " + # .format( + # 50 if idx % 4 == 2 else 0, + # 50 if idx % 4 == 1 else 0, + # 50 if idx % 2 == 1 else 100, + # 50 if idx > 0 and idx % 2 == 0 else 100 + # ) + # ) + # tags.append("".format( + # cislo.verejne_url(), cislo.kod() + # )) + # tags.append( + # "" + # .format( + # img_url, + # 50 if idx % 4 == 3 else 0, + # 50 if idx % 4 == 2 else 0, + # 50 if idx % 2 == 0 else 100, + # 50 if idx % 2 == 1 else 100 + # ) + # ) + # tags.append("") + # spirala(urls, tags, idx + 1) + # tags.append("
    ") + # spirala(urls, tags, 0) + + # context["nahledy"] = "\n".join(tags) + return context ### Výsledky -# ze setřízeného(!) seznamu všech bodů vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.) -def sloupec_s_poradim(seznam_s_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 +def sloupec_s_poradim(setrizene_body): + + # ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím aktualni_poradi = 1 sloupec_s_poradim = [] # seskupíme seznam všech bodů podle hodnot - for index in range(0, len(seznam_s_body)): + for index in range(0, len(setrizene_body)): # pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme # vypsat už jen prázdné místo, než dojdeme na správný řádek if (index + 1) < aktualni_poradi: @@ -402,10 +461,10 @@ def sloupec_s_poradim(seznam_s_body): continue velikost_skupiny = 0 # zjistíme počet po sobě jdoucích stejných hodnot - while seznam_s_body[index] == seznam_s_body[index + velikost_skupiny]: + while setrizene_body[index] == setrizene_body[index + velikost_skupiny]: velikost_skupiny = velikost_skupiny + 1 # na konci musíme ošetřit přetečení seznamu - if (index + velikost_skupiny) > len(seznam_s_body) - 1: + if (index + velikost_skupiny) > len(setrizene_body) - 1: break # pokud je velikost skupiny 1, vypíšu pořadí if velikost_skupiny == 1: @@ -418,28 +477,12 @@ def sloupec_s_poradim(seznam_s_body): aktualni_poradi = aktualni_poradi + velikost_skupiny return sloupec_s_poradim -## spočítá součet bodů získaných daným řešitelem za zadaný problém a všechny jeho podproblémy -#def __soucet_resitele_problemu(problem, resitel, cislo, soucet): -# # sečteme body za daný problém přes všechna řešení daného problému -# # od daného řešitele -# reseni_resitele = s.Reseni_Resitele.objects.filter(resitele=resitel) -# hodnoceni_resitele = problem.hodnoceni.filter(reseni__in=reseni_resitele, -# cislo_body=cislo) -# # XXX chyba na řádku výše - řešení může mít více řešitelů, asi chceme contains -# # nebo in -# for r in hodnoceni_resitele: -# soucet += r.body -# -# # a přičteme k tomu hodnocení všech podproblémů -# for p in problem.podproblem.all(): -# # i přes jméno by to měla být množina jeho podproblémů -# soucet += __soucet_resitele_problemu(p, resitel, soucet) -# return soucet - -## spočítá součet všech bodů ze všech podproblémů daného problému daného řešitele -#def body_resitele_problemu_v_cisle(problem, resitel, cislo): -# # probably FIXED: nezohledňuje číslo, do kterého se body počítají -# return __soucet_resitele_problemu(problem, resitel, cislo, 0) +# vrátí všechna čísla daného ročníku +def cisla_rocniku(rocnik, jen_verejne=True): + if jen_verejne: + return rocnik.verejna_cisla() + else: + return rocnik.cisla.all() # pro daný problém vrátí jeho nejvyšší nadproblém def hlavni_problem(problem): @@ -447,6 +490,17 @@ def hlavni_problem(problem): problem = problem.nadproblem return problem +def hlavni_problemy_rocniku(rocnik, jen_verejne=True): + hlavni_problemy = [] + for cislo in cisla_rocniku(rocnik, jen_verejne): + for problem in hlavni_problemy_cisla(cislo): + hlavni_problemy.append(problem) + hlavni_problemy_set = set(hlavni_problemy) + hlavni_problemy = list(hlavni_problemy_set) + hlavni_problemy.sort(key=lambda k:k.kod_v_rocniku()) # setřídit podle pořadí + + return hlavni_problemy + # vrátí list všech problémů s body v daném čísle, které již nemají nadproblém def hlavni_problemy_cisla(cislo): hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all() @@ -476,27 +530,32 @@ def body_resitelu_odjakziva(rocnik, resitele): for r in resitele: body_odjakziva[str(r.id)] = 0 -# POZOR! Aktuálně počítá jen za posledních 10 let od zadaného ročníku -# # Body za posledních 10 let je dobrá aproximace pro naše potřeby (výsledkovka -# # s aktivními řešiteli) -# -# body_pred_roky = [] -# for i in range(0, 10): -# body_pred_roky.append(body_resitelu_za_rocnik(rocnik-i, resitele)) -# -# for r in resitele: -# for i in range(0,10): -# body_odjakziva[str(r.id)] += body_pred_roky[i][str(r.id)] - - -# Nasledující řešení je sice správné, ale moc pomalé: - for res in Reseni.objects.prefetch_related('resitele', 'hodnoceni_set').all(): - for r in res.resitele.all(): - # daný řešitel nemusí být v naší podmnožině - if r not in resitele: continue - - for hodn in res.hodnoceni_set.all(): - pricti_body(body_odjakziva, r, hodn.body) +######################################################################### +# POZOR! Aktuálně počítá jen za posledních 10 let od zadaného ročníku # +######################################################################### + # Body za posledních 10 let je dobrá aproximace pro naše potřeby (výsledkovka + # s aktivními řešiteli) + + body_pred_roky = [] + rok = rocnik.prvni_rok + rocniky = Rocnik.objects.filter(prvni_rok__gt=rok-11) + for roc in rocniky: + body_pred_roky.append(body_resitelu_za_rocnik(roc, resitele)) + + for r in resitele: + for i in range(0,10): + body_odjakziva[str(r.id)] += body_pred_roky[i][str(r.id)] + + +# Nasledující řešení je sice správné, ale moc pomalé: +# (důsledek toho, že dotazy na joinování databázových tabulek jsou kvadratické) +# for res in Reseni.objects.prefetch_related('resitele', 'hodnoceni_set').all(): +# for r in res.resitele.all(): +# # daný řešitel nemusí být v naší podmnožině +# if r not in resitele: continue +# +# for hodn in res.hodnoceni_set.all(): +# pricti_body(body_odjakziva, r, hodn.body) return body_odjakziva # vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník @@ -514,13 +573,77 @@ def body_resitelu_za_rocnik(rocnik, aktivni_resitele): pricti_body(body_za_rocnik, resitel, hodn.body) return body_za_rocnik -# TODO: předělat na nový model -#def vysledkovka_rocniku(rocnik, jen_verejne=True): -# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve -# formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" -# """ -# -# #vyberu vsechny vysledky z rocniku +class RadekVysledkovkyRocniku(object): + """Obsahuje věci, které se hodí vědět při konstruování výsledkovky. + Umožňuje snazší práci v templatu (lepší, než seznam).""" + + def __init__(self, poradi, resitel, body_cisla_sezn, body_rocnik, body_odjakziva): + self.poradi = poradi + self.resitel = resitel + self.body_rocnik = body_rocnik + self.body_celkem_odjakziva = body_odjakziva + self.body_cisla_sezn = body_cisla_sezn + self.titul = resitel.get_titul(body_odjakziva) + +def vysledkovka_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" + """ + + ## TODO možná chytřeji vybírat aktivní řešitele + # aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají + # u alespoň jedné hodnoty něco jiného než NULL + aktivni_resitele = list(Resitel.objects.filter( + rok_maturity__gte=rocnik.druhy_rok())) + # TODO: zkusit hodnoceni__rocnik... + #.filter(hodnoceni_set__rocnik__eq=cislo_rocnik) + cisla = cisla_rocniku(rocnik, jen_verejne) + body_cisla_slov = {} + print("Jen veřejná: {}, čísla: {}".format(jen_verejne, cisla)) + for cislo in cisla: + # získáme body za číslo + _, cislobody = secti_body_za_cislo(cislo, aktivni_resitele) + body_cisla_slov[str(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) + + # setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší + setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] + setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id] + setrizene_body = [dvojice[1] for dvojice in resitel_rocnikbody_sezn] + poradi = sloupec_s_poradim(setrizene_body) + + # získáme body odjakživa + resitel_odjakzivabody_slov = body_resitelu_odjakziva(rocnik, aktivni_resitele) + + # vytvoříme jednotlivé sloupce výsledkovky + radky_vysledkovky = [] + i = 0 + for ar_id in setrizeni_resitele_id: + # seznam počtu bodů daného řešitele pro jednotlivá čísla + body_cisla_sezn = [] + for cislo in cisla: + body_cisla_sezn.append(body_cisla_slov[str(cislo.id)][str(ar_id)]) + + # vytáhneme informace pro daného řešitele + radek = RadekVysledkovkyRocniku( + poradi[i], # pořadí + Resitel.objects.get(id=ar_id), # řešitel (z id) + body_cisla_sezn, # seznam bodů za čísla + setrizene_body[i], # body za ročník (spočítané výše s pořadím) + resitel_odjakzivabody_slov[ar_id]) # body odjakživa + print("{}: číslobody - {}, ročníkbody - {}," + "odjakživabody - {}".format(radek.resitel, radek.body_cisla_sezn, + radek.body_rocnik, radek.body_celkem_odjakziva)) + radky_vysledkovky.append(radek) + print("Přikládám {}-tý řádek.".format(i)) + i += 1 + + return radky_vysledkovky + + + #vyberu vsechny vysledky z rocniku # cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__rocnik=rocnik).order_by('cislo') # if jen_verejne: # cisla_v_rocniku = cisla_v_rocniku.filter(cislo__verejna_vysledkovka=True) @@ -594,10 +717,15 @@ class RocnikView(generic.DetailView): def get_context_data(self, **kwargs): context = super(RocnikView, self).get_context_data(**kwargs) - #context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"]) - #context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False) - #context['temata_v_rocniku'] = verejna_temata(context["rocnik"]) - # FIXME: opravit vylistování témat v ročníku + # vysledkovka = True zajistí vykreslení, + # zkontrolovat, kdy se má a nemá vykreslovat + context['vysledkovka'] = True + context['cisla_s_neverejnymi'] = cisla_rocniku(context["rocnik"], jen_verejne=False) + context['cisla'] = cisla_rocniku(context["rocnik"]) + context['radky_vysledkovky'] = vysledkovka_rocniku(context["rocnik"]) + context['radky_vysledkovky_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False) + context['hlavni_problemy_v_rocniku'] = hlavni_problemy_rocniku(context["rocnik"]) + context['hlavni_problemy_v_rocniku_s_neverejnymi'] = hlavni_problemy_rocniku(context["rocnik"], jen_verejne=False) return context @@ -621,7 +749,7 @@ class ProblemView(generic.DetailView): return context -class RadekVysledkovky(object): +class RadekVysledkovkyCisla(object): """Obsahuje věci, které se hodí vědět při konstruování výsledkovky. Umožňuje snazší práci v templatu (lepší, než seznam).""" @@ -647,19 +775,22 @@ def pricti_body(slovnik, resitel, body): slovnik[str(resitel.id)] += body -def secti_body_za_rocnik(cislo, aktivni_resitele): +def secti_body_za_rocnik(rocnik, aktivni_resitele): # spočítáme všem řešitelům jejich body za ročník - resitel_rocnikbody_slov = body_resitelu_za_rocnik(cislo.rocnik, aktivni_resitele) + resitel_rocnikbody_slov = body_resitelu_za_rocnik(rocnik, aktivni_resitele) # zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(), key = lambda x: x[1], reverse = True) return resitel_rocnikbody_sezn # spočítá u řešitelů body za číslo a za jednotlivé hlavní problémy (témata) -def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy): +def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None): # 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ů) + if hlavni_problemy is None: + hlavni_problemy = hlavni_problemy_cisla(cislo) + hlavni_problemy_slovnik = {} for hp in hlavni_problemy: hlavni_problemy_slovnik[str(hp.id)] = {} @@ -697,12 +828,11 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy): return hlavni_problemy_slovnik, cislobody -def spocti_vysledkovku_cisla(cislo, context=None): +def vysledkovka_cisla(cislo, context=None): if context is None: context = {} hlavni_problemy = hlavni_problemy_cisla(cislo) - ## TODO dostat pro tyto problémy součet v daném čísle pro daného řešitele ## TODO možná chytřeji vybírat aktivní řešitele # aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají # u alespoň jedné hodnoty něco jiného než NULL @@ -715,10 +845,10 @@ def spocti_vysledkovku_cisla(cislo, context=None): 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) + resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo.rocnik, aktivni_resitele) # získáme body odjakživa - resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik.druhy_rok(), + resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik, aktivni_resitele) # řešitelé setřídění podle bodů za číslo sestupně @@ -738,7 +868,7 @@ def spocti_vysledkovku_cisla(cislo, context=None): for hp in hlavni_problemy: problemy.append(hlavni_problemy_slovnik[str(hp.id)][ar_id]) # vytáhneme informace pro daného řešitele - radek = RadekVysledkovky( + radek = RadekVysledkovkyCisla( poradi[i], # pořadí Resitel.objects.get(id=ar_id), # řešitel (z id) problemy, # seznam bodů za hlavní problémy čísla @@ -785,7 +915,7 @@ class CisloView(generic.DetailView): cislo = context['cislo'] # vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky - return spocti_vysledkovku_cisla(cislo, context) + return vysledkovka_cisla(cislo, context) # problemy = sorted(set(r.problem for r in reseni), key=lambda x:(poradi_typu[x.typ], x.kod_v_rocniku())) # #setridi problemy podle typu a poradi zadani @@ -844,13 +974,13 @@ class ArchivTemataView(generic.ListView): # content_type = 'text/plain; charset=UTF8' # #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani # -#class RocnikVysledkovkaView(RocnikView): -# model = Rocnik -# template_name = 'seminar/archiv/rocnik_vysledkovka.tex' -# #content_type = 'application/x-tex; charset=UTF8' -# #umozni rovnou stahnout TeXovsky dokument -# content_type = 'text/plain; charset=UTF8' -# #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani +class RocnikVysledkovkaView(RocnikView): + model = Rocnik + template_name = 'seminar/archiv/rocnik_vysledkovka.tex' + #content_type = 'application/x-tex; charset=UTF8' + #umozni rovnou stahnout TeXovsky dokument + content_type = 'text/plain; charset=UTF8' + #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani ### Generovani obalek class CisloObalkyStruct: