From 658f2a53c63a58880ea947716a6252c62208ef27 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 19 Jan 2021 19:25:39 +0100 Subject: [PATCH 01/13] =?UTF-8?q?WIP:=20odevzd=C3=A1v=C3=A1tkov=C3=A9=20fo?= =?UTF-8?q?rmsety?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/forms.py | 10 +++++++ .../seminar/odevzdavatko/detail.html | 4 +++ seminar/urls.py | 5 ++-- seminar/utils.py | 28 +++++++++++++++++++ seminar/views/odevzdavatko.py | 28 +++++++++++++++++-- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/seminar/forms.py b/seminar/forms.py index a7e0e404..0886f87d 100644 --- a/seminar/forms.py +++ b/seminar/forms.py @@ -301,3 +301,13 @@ class NahrajObrazekKTreeNoduForm(forms.ModelForm): model = m.Obrazek fields = ('na_web',) + +OhodnoceniReseniFormSet = inlineformset_factory(m.Reseni, m.Hodnoceni, + fields = ('problem', 'body', 'cislo_body'), + extra = 1, + widgets = { + 'problem': autocomplete.ModelSelect2( + url='autocomplete_problem_odevzdatelny', # FIXME: Dovolit i starší? + ) + } + ) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index 6cee990d..24617dda 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -43,5 +43,9 @@

Ještě nebylo hodnoceno

{% endif %} +
+{% csrf_token %} +{{ form }} +
{% endblock %} diff --git a/seminar/urls.py b/seminar/urls.py index 7fa7b0a6..3d66526b 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -1,7 +1,7 @@ from django.urls import path, include, re_path from django.contrib.auth.decorators import login_required from . import views, export -from .utils import org_required, resitel_required +from .utils import org_required, resitel_required, viewMethodSwitch from django.views.generic.base import RedirectView urlpatterns = [ @@ -174,8 +174,7 @@ urlpatterns = [ path('temp/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), path('temp/reseni///', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'), - path('temp/reseni/', org_required(views.DetailReseniView.as_view()), name='odevzdavatko_detail_reseni'), + path('temp/reseni/', org_required(viewMethodSwitch(get=views.DetailReseniView.as_view(), post=views.HodnoceniReseniView.as_view())), name='odevzdavatko_detail_reseni'), path('temp/reseni/all', org_required(views.SeznamReseniView.as_view())), path('temp/reseni/akt', org_required(views.SeznamAktualnichReseniView.as_view())), - ] diff --git a/seminar/utils.py b/seminar/utils.py index bcc67013..39abeae7 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -5,6 +5,7 @@ import datetime from django.contrib.auth import get_user_model from django.contrib.auth.decorators import permission_required from html.parser import HTMLParser +from django import views as DjangoViews from django.contrib.auth.models import AnonymousUser from django.contrib.contenttypes.models import ContentType @@ -191,3 +192,30 @@ def aktivniResitele(cislo, pouze_letosni=False): else: # spojíme querysety s řešiteli loni a letos do daného čísla return (resi_v_rocniku(loni) | resi_v_rocniku(letos, cislo)).distinct() + +def viewMethodSwitch(get, post): + """ + Vrátí view, který zavolá různé jiné views podle toho, kterou metodou je zavolán. + + Inspirováno https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#an-alternative-better-solution, jen jsem to udělal genericky. + + Parametry: + post view pro metodu POST + get view pro metodu GET + + V obou případech se míní už view jakožto funkce, takže u class-based views se už má použít .as_view() + + TODO: Podpora i pro metodu HEAD? A možná i pro FILES? + """ + + theGetView = get + thePostView = post + + class NewView(DjangoViews.View): + def get(self, request, *args, **kwargs): + return theGetView(request, *args, **kwargs) + def post(self, request, *args, **kwargs): + return thePostView(request, *args, **kwargs) + + return NewView.as_view() + diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index de8ceec3..6a593740 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -1,10 +1,11 @@ -from django.views.generic import ListView, DetailView -from django.views.generic.base import TemplateView +from django.views.generic import ListView, DetailView, FormView +from django.views.generic.detail import SingleObjectMixin from dataclasses import dataclass import datetime import seminar.models as m +import seminar.forms as f from seminar.utils import aktivniResitele, resi_v_rocniku # Co chceme? @@ -109,10 +110,31 @@ class ReseniProblemuView(ListView): # Kontext automaticky? +## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex class DetailReseniView(DetailView): model = m.Reseni template_name = 'seminar/odevzdavatko/detail.html' - # To je všechno? Najde se to podle pk... + + def aktualni_hodnoceni(self): + ... + return [] + + def get_context_data(self, **kw): + ctx = super().get_context_data(**kw) + ctx['form'] = f.OhodnoceniReseniFormSet( + initial = self.aktualni_hodnoceni() + ) + return ctx + + +class HodnoceniReseniView(SingleObjectMixin, FormView): + model = m.Reseni + template_name = 'seminar/odevzdavatko/detail.html' + form_class = f.OhodnoceniReseniFormSet + + def form_vaild(self, form): + ... + # Přehled všech řešení kvůli debugování From 3e249aef5ebafaf6a5a649966dd0c720be7136b7 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 19 Jan 2021 21:18:48 +0100 Subject: [PATCH 02/13] =?UTF-8?q?Odevzd=C3=A1vatko:=20nezobrazovat=20sezna?= =?UTF-8?q?m=20jednoho=20=C5=99e=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 6a593740..0647b770 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -1,5 +1,9 @@ from django.views.generic import ListView, DetailView, FormView +from django.views.generic.list import MultipleObjectTemplateResponseMixin,MultipleObjectMixin +from django.views.generic.base import View from django.views.generic.detail import SingleObjectMixin +from django.shortcuts import redirect +from django.urls import reverse from dataclasses import dataclass import datetime @@ -87,7 +91,8 @@ class TabulkaOdevzdanychReseniView(ListView): return ctx -class ReseniProblemuView(ListView): +# Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji? +class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View): model = m.Reseni template_name = 'seminar/odevzdavatko/seznam.html' @@ -108,6 +113,13 @@ class ReseniProblemuView(ListView): ) return qs + def get(self, request, *args, **kwargs): + self.object_list = self.get_queryset() + if self.object_list.count() == 1: + jedine_reseni = self.object_list.first() + return redirect(reverse("odevzdavatko_detail_reseni", kwargs={"pk": jedine_reseni.id})) + context = self.get_context_data() + return self.render_to_response(context) # Kontext automaticky? ## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex From cc50f459a7ded6362fdc3ab3038e2ad14bb0226f Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 26 Jan 2021 19:12:01 +0100 Subject: [PATCH 03/13] =?UTF-8?q?=C3=9Aprava=20k=C3=B3du=20k=20dod=C4=9Bl?= =?UTF-8?q?=C3=A1n=C3=AD=20filtrovateln=C3=A9=20tabulky?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 0647b770..d93b4c15 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -35,15 +35,22 @@ class TabulkaOdevzdanychReseniView(ListView): template_name = 'seminar/odevzdavatko/tabulka.html' model = m.Hodnoceni + def inicializuj_osy_tabulky(self): + """Vyrobí prvotní querysety pro sloupce a řádky, tj. seznam všech řešitelů a problémů""" + # 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, ... + self.resitele = m.Resitel.objects.all() + self.problemy = m.Problem.objects.all() + def get_queryset(self): - # FIXME: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistuje Nastavení. + 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.zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() + self.problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() qs = super().get_queryset() - qs = qs.filter(problem__in=self.zadane_problemy).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba') + qs = qs.filter(problem__in=self.problemy).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba') return qs def get_context_data(self, *args, **kwargs): @@ -51,10 +58,10 @@ class TabulkaOdevzdanychReseniView(ListView): 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.zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() + self.problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() ctx = super().get_context_data(*args, **kwargs) - ctx['problemy'] = self.zadane_problemy + ctx['problemy'] = self.problemy ctx['resitele'] = self.resitele tabulka = dict() @@ -81,7 +88,7 @@ class TabulkaOdevzdanychReseniView(ListView): hodnoty = [] for resitel in self.resitele: resiteluv_radek = [] - for problem in self.zadane_problemy: + for problem in self.problemy: if problem in tabulka and resitel in tabulka[problem]: resiteluv_radek.append(tabulka[problem][resitel]) else: From c77eb932f8232779722198e41d613aa3334a290c Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 9 Feb 2021 20:08:26 +0100 Subject: [PATCH 04/13] =?UTF-8?q?Zru=C5=A1en=20Vlo=C5=BEBodyView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stejně nic moc nedělal... --- seminar/urls.py | 5 ----- seminar/views/views_all.py | 14 -------------- 2 files changed, 19 deletions(-) diff --git a/seminar/urls.py b/seminar/urls.py index e60b91e0..aa125f02 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -123,11 +123,6 @@ urlpatterns = [ org_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky' ), - path( - 'org/vloz_body//', - org_required(views.VlozBodyView.as_view()), - name='seminar_org_vlozbody' - ), # příprava na nestatický orgorozcestník path( 'org/rozcestnik/', diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index ecbe82fa..dfee39e2 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -63,20 +63,6 @@ from seminar.utils import aktivniResitele, resi_v_rocniku def get_problemy_k_tematu(tema): return Problem.objects.filter(nadproblem = tema) - -class VlozBodyView(generic.ListView): - template_name = 'seminar/org/vloz_body.html' - - def get_queryset(self): - self.tema = get_object_or_404(Problem,id=self.kwargs['tema']) - print(self.tema) - self.problemy = Problem.objects.filter(nadproblem = self.tema) - print(self.problemy) - self.reseni = Reseni.objects.filter(problem__in=self.problemy) - print(self.reseni) - return self.reseni - - class ObalkovaniView(generic.ListView): template_name = 'seminar/org/obalkovani.html' From 0fa14b08b5dd9b305b7d4d2924691e57ac171f6d Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 9 Feb 2021 22:48:49 +0100 Subject: [PATCH 05/13] =?UTF-8?q?Dynamick=C3=BD=20formset=20na=20zad=C3=A1?= =?UTF-8?q?v=C3=A1n=C3=AD=20bod=C5=AF=20k=20=C5=99e=C5=A1en=C3=AD=20(jen?= =?UTF-8?q?=20template)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seminar/odevzdavatko/detail.html | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index 24617dda..7e6004d4 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -2,6 +2,59 @@ {% block content %} +{# FIXME: Necopypastovat! Tohle je zkopírované ze static/seminar/dynamic_formsets.js #} + + +

Řešené problémy: {{ object.problem.all | join:", " }}

Řešitelé: {{ object.resitele.all | join:", " }}

@@ -45,7 +98,31 @@
{% csrf_token %} -{{ form }} -
+{{ form.management_form }} + + +{% for subform in form %} + + + + + + +{% endfor %} +
ProblémBodyČíslo pro body
{{ subform.problem }}{{ subform.body }}{{ subform.cislo_body }}
+ + + + + + + + + + + + + + {% endblock %} From b91e639089780733d6d81f069f35a1c12e38e4fa Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 19:36:36 +0100 Subject: [PATCH 06/13] =?UTF-8?q?Odevzd=C3=A1v=C3=A1tko:=20initial=20data?= =?UTF-8?q?=20pro=20formset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index d93b4c15..3db8df7d 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -2,7 +2,7 @@ from django.views.generic import ListView, DetailView, FormView from django.views.generic.list import MultipleObjectTemplateResponseMixin,MultipleObjectMixin from django.views.generic.base import View from django.views.generic.detail import SingleObjectMixin -from django.shortcuts import redirect +from django.shortcuts import redirect, get_object_or_404 from django.urls import reverse from dataclasses import dataclass @@ -135,8 +135,15 @@ class DetailReseniView(DetailView): template_name = 'seminar/odevzdavatko/detail.html' def aktualni_hodnoceni(self): - ... - return [] + reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk']) + result = [] # Slovníky s klíči problem, body, cislo_body -- initial data pro f.OhodnoceniReseniFormSet + for hodn in m.Hodnoceni.objects.filter(reseni=reseni): + result.append( + {"problem": hodn.problem, + "body": hodn.body, + "cislo_body": hodn.cislo_body, + }) + return result def get_context_data(self, **kw): ctx = super().get_context_data(**kw) From 64d3701d0f42199a3fae1889cab5ece1fcac8db5 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 19:57:08 +0100 Subject: [PATCH 07/13] =?UTF-8?q?Success=20URL=20pro=20zad=C3=A1n=C3=AD=20?= =?UTF-8?q?bod=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 3db8df7d..5c80efe5 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -158,6 +158,10 @@ class HodnoceniReseniView(SingleObjectMixin, FormView): template_name = 'seminar/odevzdavatko/detail.html' form_class = f.OhodnoceniReseniFormSet + def get_success_url(self): + # Funkce to je jen proto, aby se dalo použít self. + return reverse('odevzdavatko_detail_reseni', kwargs={'pk': self.kwargs['pk']}) + def form_vaild(self, form): ... From 631bcd5bdbabce4ecf7e2bf6e7d138c16ef82418 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 22:59:45 +0100 Subject: [PATCH 08/13] =?UTF-8?q?Implementov=C3=A1no=20zad=C3=A1v=C3=A1n?= =?UTF-8?q?=C3=AD=20bod=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/urls.py | 2 +- seminar/views/odevzdavatko.py | 38 +++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/seminar/urls.py b/seminar/urls.py index aa125f02..074bc55e 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -169,7 +169,7 @@ urlpatterns = [ path('temp/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), path('temp/reseni///', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'), - path('temp/reseni/', org_required(viewMethodSwitch(get=views.DetailReseniView.as_view(), post=views.HodnoceniReseniView.as_view())), name='odevzdavatko_detail_reseni'), + path('temp/reseni/', org_required(viewMethodSwitch(get=views.DetailReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'), path('temp/reseni/all', org_required(views.SeznamReseniView.as_view())), path('temp/reseni/akt', org_required(views.SeznamAktualnichReseniView.as_view())), ] diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 5c80efe5..a23ebdff 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -4,14 +4,18 @@ from django.views.generic.base import View from django.views.generic.detail import SingleObjectMixin from django.shortcuts import redirect, get_object_or_404 from django.urls import reverse +from django.db import transaction from dataclasses import dataclass import datetime +import logging import seminar.models as m import seminar.forms as f from seminar.utils import aktivniResitele, resi_v_rocniku +logger = logging.getLogger(__name__) + # Co chceme? # - "Tabulku" aktuální řešitelé x zveřejněné problémy, v buňkách počet řešení # - TabulkaOdevzdanychReseniView @@ -153,17 +157,35 @@ class DetailReseniView(DetailView): return ctx -class HodnoceniReseniView(SingleObjectMixin, FormView): - model = m.Reseni +def hodnoceniReseniView(request, pk, *args, **kwargs): + reseni = get_object_or_404(m.Reseni, pk=pk) template_name = 'seminar/odevzdavatko/detail.html' form_class = f.OhodnoceniReseniFormSet + success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk}) + + formset = f.OhodnoceniReseniFormSet(request.POST) + if formset.is_valid(): + with transaction.atomic(): + # Smažeme všechna dosavadní hodnocení tohoto řešení + qs = m.Hodnoceni.objects.filter(reseni=reseni) + logger.info(f"Will delete {qs.count()} objects: {qs}") + qs.delete() + + # Vyrobíme nová podle formsetu + for form in formset: + problem = form.cleaned_data['problem'] + body = form.cleaned_data['body'] + cislo_body = form.cleaned_data['cislo_body'] + hodnoceni = m.Hodnoceni( + problem=problem, + body=body, + cislo_body=cislo_body, + reseni=reseni, + ) + logger.info(f"Creating Hodnoceni: {hodnoceni}") + hodnoceni.save() - def get_success_url(self): - # Funkce to je jen proto, aby se dalo použít self. - return reverse('odevzdavatko_detail_reseni', kwargs={'pk': self.kwargs['pk']}) - - def form_vaild(self, form): - ... + return redirect(success_url) # Přehled všech řešení kvůli debugování From 03a4bf585d882a1c074e8953e3ba2cf96cdc2308 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 23:11:40 +0100 Subject: [PATCH 09/13] =?UTF-8?q?Fix=20template,=20aby=20vzorov=C3=A1=20ta?= =?UTF-8?q?bulka=20byla=20mimo=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/odevzdavatko/detail.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index 7e6004d4..ddfb9e20 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -112,6 +112,9 @@ $(document).ready(function(){ + + + @@ -121,8 +124,6 @@ $(document).ready(function(){ - - {% endblock %} From d33d2b1b91693736de79ec86622f3b469512dd30 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 23:37:43 +0100 Subject: [PATCH 10/13] Whitespace trim --- seminar/templates/seminar/odevzdavatko/detail.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index ddfb9e20..000167a3 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -124,6 +124,4 @@ $(document).ready(function(){ - - {% endblock %} From 9d79c052feaa7a3a1793b1e6264b023f8c8c43a5 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 23:37:59 +0100 Subject: [PATCH 11/13] =?UTF-8?q?P=C3=A1r=20n=C3=A1m=C4=9Bt=C5=AF=20na=20z?= =?UTF-8?q?lep=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index a23ebdff..0c182695 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -163,6 +163,8 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): form_class = f.OhodnoceniReseniFormSet success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk}) + # FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově + # Also: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#django.forms.ModelForm formset = f.OhodnoceniReseniFormSet(request.POST) if formset.is_valid(): with transaction.atomic(): From 98202902d36c0175c952ec9bff9404dba2577cfd Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 23:49:42 +0100 Subject: [PATCH 12/13] =?UTF-8?q?Zm=C4=9Bna=20z=20inlinemodelformsetu=20na?= =?UTF-8?q?=20oby=C4=8Dejn=C3=BD=20formset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Teď už initial funguje správně --- seminar/forms.py | 11 ++++++++--- seminar/templates/seminar/odevzdavatko/detail.html | 8 ++++---- seminar/views/odevzdavatko.py | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/seminar/forms.py b/seminar/forms.py index 71402a58..c64095c6 100644 --- a/seminar/forms.py +++ b/seminar/forms.py @@ -2,6 +2,7 @@ from django import forms from dal import autocomplete from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth.models import User +from django.forms import formset_factory from django.forms.models import inlineformset_factory from .models import Skola, Resitel, Osoba, Problem @@ -302,12 +303,16 @@ class NahrajObrazekKTreeNoduForm(forms.ModelForm): fields = ('na_web',) -OhodnoceniReseniFormSet = inlineformset_factory(m.Reseni, m.Hodnoceni, - fields = ('problem', 'body', 'cislo_body'), - extra = 1, +class JednoHodnoceniForm(forms.ModelForm): + class Meta: + model = m.Hodnoceni + fields = ('problem', 'body', 'cislo_body') widgets = { 'problem': autocomplete.ModelSelect2( url='autocomplete_problem_odevzdatelny', # FIXME: Dovolit i starší? ) } + +OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm, + extra = 0, ) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index 000167a3..dd4979f3 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -38,18 +38,18 @@ function deleteForm(prefix, btn) { // Credit: https://simpleit.rocks/python/django/dynamic-add-form-with-add-button-in-django-modelformset-template/ $(document).ready(function(){ $('#pridat_hodnoceni').click(function() { - var form_idx = $('#id_hodnoceni_set-TOTAL_FORMS').val(); + var form_idx = $('#id_form-TOTAL_FORMS').val(); var new_form = $('#empty_form').html().replace(/__prefix__/g, form_idx); $('#form_set').append(new_form); // Newly created form has not the binding between remove button and remove function // We need to add it manually $('.smazat_hodnoceni').click(function(){ - deleteForm("hodnoceni_set",this); + deleteForm("form",this); }); - $('#id_hodnoceni_set-TOTAL_FORMS').val(parseInt(form_idx) + 1); + $('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1); }); $('.smazat_hodnoceni').click(function(){ - deleteForm("hodnoceni_set",this); + deleteForm("form",this); }); }); diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 0c182695..e81f119f 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -166,6 +166,8 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): # FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově # Also: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#django.forms.ModelForm formset = f.OhodnoceniReseniFormSet(request.POST) + # TODO: Napsat validaci formuláře a formsetu + # TODO: Implementovat větev, kdy formulář validní není. if formset.is_valid(): with transaction.atomic(): # Smažeme všechna dosavadní hodnocení tohoto řešení From 4a930542b8c45f47841168d1f55e4f9f2090e3b8 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 16 Feb 2021 23:52:20 +0100 Subject: [PATCH 13/13] =?UTF-8?q?Zru=C5=A1ena=20tabulka=20s=20hodnocen?= =?UTF-8?q?=C3=ADmi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Už je tam formset --- .../templates/seminar/odevzdavatko/detail.html | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index dd4979f3..6344e0a5 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -80,22 +80,7 @@ $(document).ready(function(){ {% endif %} {# Hodnocení: #} -{# FIXME: Udělat jako formulář #}

Hodnocení:

-{% if object.hodnoceni_set.all %} - - -{% for h in object.hodnoceni_set.all %} - - - - -{% endfor %} -
ProblémBodyČíslo pro body
{{ h.problem }}{{ h.body }}{{ h.cislo_body }}
-{% else %} -

Ještě nebylo hodnoceno

-{% endif %} -
{% csrf_token %} {{ form.management_form }}