Browse Source

Merge remote-tracking branch 'origin/data_migrations' into treenode_editor

export_seznamu_prednasek
parent
commit
34d0284f0d
  1. 33
      seminar/templates/seminar/nahraj_reseni.html
  2. 120
      seminar/views/views_all.py

33
seminar/templates/seminar/nahraj_reseni.html

@ -15,18 +15,41 @@
<form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' %}" method="post"> <form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' %}" method="post">
{% csrf_token %} {% csrf_token %}
{{ form }} {{ form }}
<hr>
{{ prilohy.management_form }} {{ prilohy.management_form }}
<h4>Přilohy s řešením</h4> <h4>Soubory s řešením</h4>
<div id="form_set"> <div id="form_set">
{% for form in prilohy.forms %} {% for form in prilohy.forms %}
<div class="attachment"> <div class="attachment">
{{ form.non_field_errors }} {{ form.non_field_errors }}
{{ form.errors }} {# {{ form.errors }} FIXME: možná tohle chceme zobrazovat? #}
<table class='no_error'> <table class='form' id=''>
{{ form }}
<tr>
{% for field in form.visible_fields %}
<td>
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
{{ field.label }}:
</label>
</td>
<td {% if field.help_text %} class="field-with-comment"{% endif %}>
{{ field }}
<span class="field-comment">{{ field.help_text|safe }}
</td>
<td><span class="field-error">{{ field.errors }}</span></td>
{# TODO #}
{% endfor %}
</tr>
</table> </table>
<input type="button" value="Odebrat přílohu" class="remove_attachment" id="{{form.prefix}}-jsremove"> <input type="button" value="Odebrat přílohu" class="remove_attachment" id="{{form.prefix}}-jsremove">
</div> </div>
@ -45,7 +68,7 @@
</div> </div>
<hr> <hr>
<h4>Odevzdat řešení</h4> <h4>Odevzdat řešení</h4>
<input type="submit" value="Odevzdat"> <input type="submit" value="Odevzdat">
</form> </form>

120
seminar/views/views_all.py

@ -599,7 +599,8 @@ def body_resitelu(resitele, za, odjakziva=True):
reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi) )) reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi) ))
elif cislo and not odjakziva: # Body se sčítají za dané číslo. elif cislo and not odjakziva: # Body se sčítají za dané číslo.
body_k_zapocteni = Sum('reseni__hodnoceni__body', body_k_zapocteni = Sum('reseni__hodnoceni__body',
filter=( Q(reseni__hodnoceni__cislo_body=cislo) )) 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ě. 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', body_k_zapocteni = Sum('reseni__hodnoceni__body',
filter= Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte=rok)) filter= Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte=rok))
@ -639,10 +640,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
## TODO možná chytřeji vybírat aktivní ř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í # 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 # u alespoň jedné hodnoty něco jiného než NULL
aktivni_resitele = list(Resitel.objects.filter( aktivni_resitele = list(resi_v_rocniku(rocnik))
rok_maturity__gte=rocnik.druhy_rok()))
# TODO: zkusit hodnoceni__rocnik...
#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik)
cisla = cisla_rocniku(rocnik, jen_verejne) cisla = cisla_rocniku(rocnik, jen_verejne)
body_cisla_slov = {} body_cisla_slov = {}
for cislo in cisla: for cislo in cisla:
@ -746,10 +744,15 @@ def pricti_body(slovnik, resitel, body):
slovnik[resitel.id] += body slovnik[resitel.id] += body
def secti_body_za_rocnik(rocnik, aktivni_resitele): def secti_body_za_rocnik(za, aktivni_resitele):
""" Spočítá body za ročník, setřídí je sestupně a vrátí jako seznam.""" """ 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 do
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, rocnik, False) resitel_rocnikbody_slov = body_resitelu(aktivni_resitele, za, False)
# 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)
@ -795,6 +798,9 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None):
# a mít více řešitelů # a mít více řešitelů
for resitel in list(reseni.resitele.all()): for resitel in list(reseni.resitele.all()):
if resitel not in aktivni_resitele:
print("Skipping {}".format(resitel.id))
continue
pricti_body(cislobody, resitel, body) pricti_body(cislobody, resitel, body)
pricti_body(nadproblem_slovnik, resitel, body) pricti_body(nadproblem_slovnik, resitel, body)
return hlavni_problemy_slovnik, cislobody return hlavni_problemy_slovnik, cislobody
@ -807,16 +813,13 @@ def vysledkovka_cisla(cislo, context=None):
## TODO možná chytřeji vybírat aktivní ř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í # 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 # u alespoň jedné hodnoty něco jiného než NULL
aktivni_resitele = list(Resitel.objects.filter( aktivni_resitele = list(aktivniResitele(cislo.rocnik.rocnik, cislo.poradi))
rok_maturity__gte=cislo.rocnik.druhy_rok()))
# TODO: zkusit hodnoceni__rocnik...
#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik)
# získáme body za číslo # získáme body za číslo
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.rocnik, aktivni_resitele) resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo, aktivni_resitele)
# 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)
@ -918,58 +921,73 @@ class RocnikVysledkovkaView(RocnikView):
#vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani
### Generovani obalek ### Generovani obalek
def resi_v_rocniku(rocnik, cislo=None):
""" Vrátí seznam řešitelů, co vyřešili nějaký problém v daném ročníku, do daného čísla.
Parametry:
rocnik (typu Rocnik) ročník, ze kterého chci řešitele, co něco odevzdali
cislo (typu Cislo) číslo, do kterého včetně se počítá, že v daném
ročníku řešitel něco poslal.
Pokud není zadané, počítají se všechna řešení z daného ročníku.
Výstup:
QuerySet objektů typu Resitel """
if cislo is None:
# filtrujeme pouze podle ročníku
letosni_reseni = Reseni.objects.filter(hodnoceni__cislo_body__rocnik = rocnik)
else: # filtrujeme podle ročníku i čísla
letosni_reseni = Reseni.objects.filter(hodnoceni__cislo_body__rocnik = rocnik,
hodnoceni__cislo_body__poradi__lte=cislo.poradi)
class CisloObalkyStruct: # vygenerujeme queryset řešitelů, co letos něco poslali
rocnik = None letosni_resitele = Resitel.objects.none()
cisla = None for reseni in letosni_reseni:
letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok())
return letosni_resitele.distinct()
# Vraci QuerySet aktualnich resitelu = nekdy neco poslali, ale jeste neodmaturovali def aktivniResitele(rocnik, cislo):
def aktualniResitele(rocnik): """ Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali
a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla).
Parametry:
rocnik (typu int) číslo ročníku, o který se jedná
cislo (typu int) pořadí čísla, o které se jedná
"""
letos = Rocnik.objects.get(rocnik = rocnik) letos = Rocnik.objects.get(rocnik = rocnik)
return Resitel.objects.filter(rok_maturity__gt = letos.prvni_rok) #TODO: co se stane, když zadané kombinace neexistují? ošetřit
# # ALERT: pokud nekdo nema vypleny rok maturity, tak neni aktualni, protoze Karel Tesar a jini aktualni_cislo = Cislo.objects.get(rocnik = rocnik, poradi = cislo)
# return Resitel.objects.filter(Q(rok_maturity__gt = letos.prvni_rok)|Q(rok_maturity = None)) loni = Rocnik.objects.get(rocnik = rocnik - 1)
# Vraci QuerySet aktivnich resitelu =
# jeste neodmaturovali &&
# (pokud je aktualni cislo mensi nez 3, pak (letos || loni) neco poslali
# jinak letos neco poslali)
def aktivniResitele(rocnik,cislo):
letos = CisloObalkyStruct()
loni = CisloObalkyStruct()
aktualni_resitele = aktualniResitele(rocnik)
letos.rocnik = Rocnik.objects.get(rocnik = rocnik)
loni.rocnik = Rocnik.objects.get(rocnik = int(rocnik)-1)
letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik, cislo__lte = cislo)
loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik)
if int(cislo) > 3:
problemy = Problem.objects.filter(cislo_zadani__in = letos.cisla)
else:
problemy = Problem.objects.filter(
Q(cislo_zadani__in = letos.cisla) | Q(cislo_zadani__in = loni.cisla) )
resitele = aktualni_resitele.filter(reseni__in = Reseni.objects.filter(
problem__in=problemy)).distinct()
return resitele
# detekujeme, zda jde o první tři čísla či nikoli
zacatek_rocniku = True
try:
if int(aktualni_cislo.poradi) > 3:
zacatek_rocniku = False
except ValueError:
# pravděpodobně se jedná o číslo 7-8
zacatek_rocniku = False
if not zacatek_rocniku:
return resi_v_rocniku(letos)
else:
# spojíme querysety s řešiteli loni a letos do daného čísla
return (resi_v_rocniku(loni) | resi_v_rocniku(letos, aktualni_cislo)).distinct()
def cisloObalkyView(request,rocnik,cislo): def cisloObalkyView(request, rocnik, cislo):
return obalkyView(request,aktivniResitele(rocnik,cislo)) return obalkyView(request, aktivniResitele(rocnik, cislo))
def obalkyView(request,resitele): def obalkyView(request, resitele):
tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content
tempdir = tempfile.mkdtemp() tempdir = tempfile.mkdtemp()
with open(tempdir+"/obalky.tex","w") as texfile: with open(tempdir+"/obalky.tex","w") as texfile:
texfile.write(tex) texfile.write(tex.decode())
shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.pdf'),tempdir) shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.pdf'), tempdir)
subprocess.call(["pdflatex","obalky.tex"],cwd = tempdir) subprocess.call(["pdflatex","obalky.tex"], cwd = tempdir)
with open(tempdir+"/obalky.pdf","rb") as pdffile: with open(tempdir+"/obalky.pdf","rb") as pdffile:
response = HttpResponse(pdffile.read(),content_type='application/pdf') response = HttpResponse(pdffile.read(), content_type='application/pdf')
shutil.rmtree(tempdir) shutil.rmtree(tempdir)
return response return response

Loading…
Cancel
Save