From ab69ca3fe2936532c80e51ad734d3f72039a1700 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 21:56:25 +0100 Subject: [PATCH 01/15] Fix safe_father_of_first --- seminar/treelib.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index cfb49d86..def0f6da 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -20,7 +20,11 @@ def safe_pred(node): # A to samé pro .father_of_first def safe_father_of_first(node): - return node.prev + first_brother = node + while safe_pred(first_brother) is not None: + first_brother = safe_pred(first_brother) + try: + return first_brother.father_of_first except ObjectDoesNotExist: return None From 8fcb1b0871018ddf6387288d0881f5094cb1c521 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 22:32:02 +0100 Subject: [PATCH 02/15] Treelib: Fix all_brothers, all_proper_brothers --- seminar/treelib.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index def0f6da..946e61fd 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -65,14 +65,29 @@ def general_prev(node): # pred nyní nemá žádné potomky, takže je to poslední rekurzivní potomek původního předchůdce return pred -# Generátor bratrů +# Generátor pravých bratrů (konkrétně sebe a následujících potomků) # Generátor potomků níže spoléhá na to, že se tohle dá volat i s parametrem None. -def all_brothers(node): +def me_and_right_brothers(node): current = node while current is not None: yield current current = current.succ +# Generátor všech sourozenců (vč. sám sebe) +def all_brothers(node): + # Najdeme prvního bratra + fb = first_brother(node) + marb = me_and_all_brothers(fb) + for cur in marb: + yield cur + +def all_proper_brothers(node): + all = all_brothers(node) + for br in all: + if br is node: + continue + yield br + # Generátor potomků def all_children(node): brothers = all_brothers(node.first_child) From 63dd0da97c524f2582aef836eed1fbd090404688 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 22:36:07 +0100 Subject: [PATCH 03/15] Treelib: Add first_brother --- seminar/treelib.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index 946e61fd..8cf01660 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -18,13 +18,17 @@ def safe_pred(node): except ObjectDoesNotExist: return None +def first_brother(node): + brother = node + while safe_pred(brother) is not None: + brother = safe_pred(brother) + return brother + # A to samé pro .father_of_first def safe_father_of_first(node): - first_brother = node - while safe_pred(first_brother) is not None: - first_brother = safe_pred(first_brother) + first = first_brother(node) try: - return first_brother.father_of_first + return first.father_of_first except ObjectDoesNotExist: return None From bf96cac66f3cdc7e2e1fbf6e6783721865611556 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 22:40:06 +0100 Subject: [PATCH 04/15] Treelib: get_next_brother_of_type --- seminar/treelib.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index 8cf01660..c1b5531b 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -77,6 +77,11 @@ def me_and_right_brothers(node): yield current current = current.succ +def right_brothers(node): + generator = me_and_right_brothers(node.succ) + for item in generator: + yield item + # Generátor všech sourozenců (vč. sám sebe) def all_brothers(node): # Najdeme prvního bratra @@ -103,9 +108,12 @@ def all_children(node): ## Filtrační hledání # Najdi dalšího bratra nějakého typu, nebo None. # hledá i podtřídy, i.e. get_next_brother_of_type(neco, TreeNode) je prostě succ. -def get_next_brother_of_type(current, type): - pass -def get_prev_brother_of_type(current, type): +def get_next_brother_of_type(node, type): + for current in right_brothers(node) + if isinstance(current, type): + return current + +def get_prev_brother_of_type(node, type): pass # Totéž pro "the-right-order" pořadí From 95f3b9b120ec594c87c677a8f32bb8b902e3de42 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 22:44:27 +0100 Subject: [PATCH 05/15] Treelib missing : --- seminar/treelib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index c1b5531b..1aa096bb 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -109,7 +109,7 @@ def all_children(node): # Najdi dalšího bratra nějakého typu, nebo None. # hledá i podtřídy, i.e. get_next_brother_of_type(neco, TreeNode) je prostě succ. def get_next_brother_of_type(node, type): - for current in right_brothers(node) + for current in right_brothers(node): if isinstance(current, type): return current From 91c2490d01a08ea249567592659a13b97c7986c9 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 23:02:14 +0100 Subject: [PATCH 06/15] Treelib typo --- seminar/treelib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index 1aa096bb..709e6d98 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -86,7 +86,7 @@ def right_brothers(node): def all_brothers(node): # Najdeme prvního bratra fb = first_brother(node) - marb = me_and_all_brothers(fb) + marb = me_and_right_brothers(fb) for cur in marb: yield cur From 2888975eab470be12273db8aae5778c9bc977659 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 23:18:32 +0100 Subject: [PATCH 07/15] Treelib fix --- seminar/treelib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/seminar/treelib.py b/seminar/treelib.py index 709e6d98..8ad33c9c 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -19,6 +19,8 @@ def safe_pred(node): return None def first_brother(node): + if node is None: + return None brother = node while safe_pred(brother) is not None: brother = safe_pred(brother) From 8071cc255468b214213d4e84b3abf18aaee36bfc Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 23:22:46 +0100 Subject: [PATCH 08/15] =?UTF-8?q?Treelib=20dal=C5=A1=C3=AD=20TODO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/treelib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/seminar/treelib.py b/seminar/treelib.py index 8ad33c9c..f9ba04df 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -1,6 +1,7 @@ from django.core.exceptions import ObjectDoesNotExist # NOTE: node.prev a node.succ jsou implementovány přímo v models.TreeNode # TODO: Všechny tyto funkce se naivně spoléhají na to, že jako parametr dostanou nějaký TreeNode (některé možná zvládnou i None) +# TODO: Chceme, aby všechno nějak zvládlo None jako parametr. # Slouží k debugování pro rychlé získání představy o podobě podstromu pod tímto TreeNode. def print_tree(node,indent=0): From 78a667b42c4798eee73c4fd6f592026be67e0982 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Wed, 18 Mar 2020 23:33:59 +0100 Subject: [PATCH 09/15] =?UTF-8?q?Treelib:=20gener=C3=A1tor=20a=20funkce=20?= =?UTF-8?q?na=20hled=C3=A1n=C3=AD=20n=C3=A1sleduj=C3=ADc=C3=ADch=20nod?= =?UTF-8?q?=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/treelib.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index f9ba04df..6e531c63 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -107,6 +107,12 @@ def all_children(node): yield br # Generátor následníků v "the-right-order" +# Bez tohoto vrcholu +def all_following(node): + current = general_next(node) + while current is not None: + yield current + current = general_next(current) ## Filtrační hledání # Najdi dalšího bratra nějakého typu, nebo None. @@ -115,15 +121,32 @@ def get_next_brother_of_type(node, type): for current in right_brothers(node): if isinstance(current, type): return current + return None def get_prev_brother_of_type(node, type): - pass + # Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem. + current = node + while safe_pred(current) is not None: + current = safe_pred(current) + if isinstance(current, type): + return current + return None # Totéž pro "the-right-order" pořadí -def get_next_node_of_type(current, type): - pass -def get_next_node_of_type(current, type): - pass +def get_next_node_of_type(node, type): + for cur in all_folowing(node): + if isinstance(cur, type): + return cur + return None + +def get_prev_node_of_type(node, type): + # Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem. + current = node + while general_prev(current) is not None: + current = general_prev(current) + if isinstance(current, type): + return current + return None From 62d6c0df02130a0102d8da72d6a347a548f8b11b Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Thu, 19 Mar 2020 00:22:18 +0100 Subject: [PATCH 10/15] =?UTF-8?q?Treelib:=20vyr=C3=A1b=C3=ADme=20nov=C3=A9?= =?UTF-8?q?=20uzly...=20snad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/treelib.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index 6e531c63..0f21454c 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -153,11 +153,25 @@ def get_prev_node_of_type(node, type): # Editace stromu: def create_node_after(predecessor, type, **kwargs): - pass + new_node = type.objects.create(**kwargs) + new_node.save() + succ = predecessor.succ + predecessor.succ = new_node + predecessor.save() + new_node.succ = succ + new_node.save() # Vyrábí prvního syna, ostatní nalepí za (existují-li) def create_child(parent, type, **kwargs): - pass + new_node = type.objects.create(**kwargs) + new_node.save() + orig_child = parent.first_child + parent.first_child = new_node + parent.save() + if orig_child is not None: + # Přidáme původního prvního syna jako potomka nového vrcholu + new_node.succ = orig_child + new_node.save() def create_node_before(some, arguments, but, i, dont, know, which, yet): pass From ac0c616e1314e8208083864c392c9fb19c134b79 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Thu, 19 Mar 2020 00:37:08 +0100 Subject: [PATCH 11/15] =?UTF-8?q?Treelib:=20obecn=C3=BD=20swap=20implement?= =?UTF-8?q?ovat=20nebudu.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moc edge-cases. --- seminar/treelib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index 0f21454c..f890868b 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -179,7 +179,7 @@ def create_node_before(some, arguments, but, i, dont, know, which, yet): # ValueError, pokud je (aspoň) jeden parametr None def swap(node, other): - pass + raise NotImplementedError("YAGNI (You aren't gonna need it).") def swap_pred(node): pass From d84cce71f32fd1a2aaa780b6d4c5b01467696065 Mon Sep 17 00:00:00 2001 From: "Tomas \"Jethro\" Pokorny" Date: Thu, 19 Mar 2020 00:50:39 +0100 Subject: [PATCH 12/15] seminar | Prvni fungujici verze renderovani treenode struktury. --- seminar/templates/seminar/treenode.html | 10 + .../templates/seminar/treenode_recursive.html | 28 +++ seminar/templatetags/treenodes.py | 49 ++++ seminar/urls.py | 8 +- seminar/views/views_all.py | 219 ++++++++---------- 5 files changed, 191 insertions(+), 123 deletions(-) create mode 100644 seminar/templates/seminar/treenode.html create mode 100644 seminar/templates/seminar/treenode_recursive.html create mode 100644 seminar/templatetags/treenodes.py diff --git a/seminar/templates/seminar/treenode.html b/seminar/templates/seminar/treenode.html new file mode 100644 index 00000000..0fd734ef --- /dev/null +++ b/seminar/templates/seminar/treenode.html @@ -0,0 +1,10 @@ +{% extends "seminar/archiv/base_ulohy.html" %} + +{% load comments %} + +{% block content %} + +{%with obj=tnldata depth=1 template_name="seminar/treenode_recursive.html" %} + {%include template_name%} +{%endwith%} +{% endblock content %} diff --git a/seminar/templates/seminar/treenode_recursive.html b/seminar/templates/seminar/treenode_recursive.html new file mode 100644 index 00000000..0cf37d9a --- /dev/null +++ b/seminar/templates/seminar/treenode_recursive.html @@ -0,0 +1,28 @@ +{% load treenodes %} +{# {{depth}} #} +
+{% if obj.node|isRocnik %} + Ročník {{obj.node.rocnik}} +{% elif obj.node|isCislo %} + Číslo {{obj.node.cislo}} +{% elif obj.node|isTemaVCisle %} + Téma {{obj.node.tema.nazev}} +{% elif obj.node|isUlohaZadani %} +Úloha {{obj.node.uloha.kod_v_rocniku}} ({{obj.node.uloha.max_body}} b) +{% elif obj.node|isUlohaVzorak %} +Řešení: {{obj.node.uloha.kod_v_rocniku}} +{% elif obj.node|isText %} +{{obj.node.text.na_web}} +{% else %} +Objekt jiného typu {{obj.node}} +{% endif %} + {%if obj.children %} +
+ {%for ch in obj.children %} + {%with obj=ch depth=depth|add:"1" template_name="seminar/treenode_recursive.html" %} + {%include template_name%} + {%endwith%} + {%endfor%} +
+ {%endif%} +
diff --git a/seminar/templatetags/treenodes.py b/seminar/templatetags/treenodes.py new file mode 100644 index 00000000..0d60765e --- /dev/null +++ b/seminar/templatetags/treenodes.py @@ -0,0 +1,49 @@ +from django import template +import seminar.models as m + +register = template.Library() + +@register.filter +def isRocnik(value): + return isinstance(value, m.RocnikNode) + +@register.filter +def isCislo(value): + return isinstance(value, m.CisloNode) + +@register.filter +def isCast(value): + return isinstance(value, m.CastNode) + +@register.filter +def isText(value): + return isinstance(value, m.TextNode) + +@register.filter +def isTemaVCisle(value): + return isinstance(value, m.TemaVCisleNode) + +@register.filter +def isKonfera(value): + return isinstance(value, m.KonferaNode) + +@register.filter +def isClanek(value): + return isinstance(value, m.ClanekNode) + +@register.filter +def isUlohaVzorak(value): + return isinstance(value, m.UlohaVzorakNode) + +@register.filter +def isUlohaZadani(value): + return isinstance(value, m.UlohaZadaniNode) + +@register.filter +def isPohadka(value): + return isinstance(value, m.PohadkaNode) + +#@register.filter +#def isOtisteneReseniNode(value): +# return isinstance(value, m.OtisteneReseniNode) + diff --git a/seminar/urls.py b/seminar/urls.py index 1d5348da..002170c4 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -25,6 +25,7 @@ urlpatterns = [ path('rocnik//', views.RocnikView.as_view(), name='seminar_rocnik'), #path('cislo/./', views.CisloView.as_view(), name='seminar_cislo'), path('problem//', views.ProblemView.as_view(), name='seminar_problem'), + path('treenode//', views.TreeNodeView.as_view(), name='seminar_treenode'), #path('problem/(?P\d+)/(?P\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), # Soustredeni @@ -107,9 +108,6 @@ urlpatterns = [ path('auth/login/', views.LoginView.as_view(), name='login'), path('auth/logout/', views.LogoutView.as_view(), name='logout'), path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'), - path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), - path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'), - path('autocomplete/problem/odevzdatelny',views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), path('auth/reset_password/', views.PasswordResetView.as_view(), name='reset_password'), path('auth/change_password/', views.PasswordChangeView.as_view(), name='change_password'), path('auth/reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), @@ -117,6 +115,10 @@ urlpatterns = [ path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), + # Autocomplete + path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), + path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'), + path('autocomplete/problem/odevzdatelny',views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), path('temp/add_solution', views.AddSolutionView.as_view(),name='seminar_vloz_reseni'), path('temp/submit_solution', views.SubmitSolutionView.as_view(),name='seminar_nahraj_reseni'), diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 3cfb0535..40357769 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -19,7 +19,7 @@ from django.db import transaction import seminar.models as s from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva -from seminar import utils +from seminar import utils,treelib from .unicodecsv import UnicodeWriter from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm import seminar.forms as f @@ -83,131 +83,110 @@ class ObalkovaniView(generic.ListView): context['cislo'] = self.cislo return context +class TNLData(object): + def __init__(self,anode): + self.node = anode + self.children = [] +def treenode_strom_na_seznamy(node): + out = TNLData(node) + for ch in treelib.all_children(node): + outitem = treenode_strom_na_seznamy(ch) + out.children.append(outitem) + return out -def AktualniZadaniView(request): - nastaveni = get_object_or_404(Nastaveni) - verejne = nastaveni.aktualni_cislo.verejne() - problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') - ulohy = problemy.filter(typ = 'uloha').order_by('kod') - serialy = problemy.filter(typ = 'serial').order_by('kod') - jednorazove_problemy = [ulohy, serialy] - return render(request, 'seminar/zadani/AktualniZadani.html', - {'nastaveni': nastaveni, - 'jednorazove_problemy': jednorazove_problemy, - 'temata': verejna_temata(nastaveni.aktualni_rocnik), - 'verejne': verejne, - }, - ) - -def ZadaniTemataView(request): - nastaveni = get_object_or_404(Nastaveni) - temata = verejna_temata(nastaveni.aktualni_rocnik) - for t in temata: - if request.user.is_staff: - t.prispevky = t.prispevek_set.filter(problem=t) - else: - t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) - return render(request, 'seminar/zadani/Temata.html', - { - 'temata': temata, - } - ) +class TreeNodeView(generic.DetailView): + model = s.TreeNode + template_name = 'seminar/treenode.html' -# TODO Napsat tuto funkci znovu rekurzivně podle Jethrorad. Potom se podívat, jak lehce se dá modifikovat pro Rozcestník. Pokud lehce, rozšířit ji. Pokud složitě - použít tuhle -def vytahniZLesaSeznam(tematko, koren, pouze_zajimave=False): - returnVal = [] - - stack = [] - stack.append((koren.first_child, 0, False)) #Tuple of node, depth and relevance - - while len(stack) > 0: - wn, wd, wr = stack.pop() - - if wn.succ != None: - stack.append((wn.succ, wd, wr)) - if isinstance(wn, s.TemaVCisleNode): - print("TEMA") - print(wn.tema.id) - print(tematko.id) - if wn.tema.id == tematko.id: - returnVal.append((posledni_cislo, 0)) - print("PRIDANO") - wr = True - wd = 1 - - if wn.srolovatelne: - tagOpen = s.Text(na_web = "Otevírací srolovací tag") - tagOpenNode = s.TextNode(text = tagOpen) - tagClose = s.Text(na_web = "Zavírací srolovací tag") - tagCloseNode = s.TextNode(text = tagClose) - stack.append((tagCloseNode, wd, True)) - - if wn.first_child != None: - stack.append((wn.first_child, wd + 1, wr)) - - if isinstance(wn, s.CisloNode): - posledni_cislo = wn - print(wn) - - if wr: - print("ZAJIMAVE") - if pouze_zajimave: - if not wn.zajimave: - continue - returnVal.append((wn, wd)) - return returnVal - -def TematkoView(request, rocnik, tematko): - nastaveni = s.Nastaveni.objects.first() - rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik) - tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) - seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) - for node, depth in seznam: - if node.isinstance(node, s.KonferaNode): - raise Exception("Not implemented yet") - if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou - pass - - return render(request, 'seminar/tematka/toaletak.html', {}) + def get_context_data(self,**kwargs): + context = super().get_context_data(**kwargs) + context['tnldata'] = treenode_strom_na_seznamy(self.object) + return context -def TemataRozcestnikView(request): - print("=============================================") - nastaveni = s.Nastaveni.objects.first() - tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) - tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku - for tematko_object in tematka_objects: - print("AKTUALNI TEMATKO") - print(tematko_object.id) - odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu - print(odkazy) - cisla = [] # List tuplů (nazev cisla, list odkazů) - vcisle = [] - cislo = None - for odkaz in odkazy: - if odkaz[1] == 0: - if cislo != None: - cisla.append((cislo, vcisle)) - cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()) - vcisle = [] - else: - print(odkaz[0].getOdkaz()) - vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())) - if cislo != None: - cisla.append((cislo, vcisle)) - - print(cisla) - tematka.append({ - "kod" : tematko_object.kod, - "nazev" : tematko_object.nazev, - "abstrakt" : tematko_object.abstrakt, - "obrazek": tematko_object.obrazek, - "cisla" : cisla - }) - return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik}) - + +#def AktualniZadaniView(request): +# nastaveni = get_object_or_404(Nastaveni) +# verejne = nastaveni.aktualni_cislo.verejne() +# problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') +# ulohy = problemy.filter(typ = 'uloha').order_by('kod') +# serialy = problemy.filter(typ = 'serial').order_by('kod') +# jednorazove_problemy = [ulohy, serialy] +# return render(request, 'seminar/zadani/AktualniZadani.html', +# {'nastaveni': nastaveni, +# 'jednorazove_problemy': jednorazove_problemy, +# 'temata': verejna_temata(nastaveni.aktualni_rocnik), +# 'verejne': verejne, +# }, +# ) +# +#def ZadaniTemataView(request): +# nastaveni = get_object_or_404(Nastaveni) +# temata = verejna_temata(nastaveni.aktualni_rocnik) +# for t in temata: +# if request.user.is_staff: +# t.prispevky = t.prispevek_set.filter(problem=t) +# else: +# t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) +# return render(request, 'seminar/zadani/Temata.html', +# { +# 'temata': temata, +# } +# ) +# +# +# +#def TematkoView(request, rocnik, tematko): +# nastaveni = s.Nastaveni.objects.first() +# rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik) +# tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) +# seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) +# for node, depth in seznam: +# if node.isinstance(node, s.KonferaNode): +# raise Exception("Not implemented yet") +# if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou +# pass +# +# return render(request, 'seminar/tematka/toaletak.html', {}) +# +# +#def TemataRozcestnikView(request): +# print("=============================================") +# nastaveni = s.Nastaveni.objects.first() +# tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) +# tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku +# for tematko_object in tematka_objects: +# print("AKTUALNI TEMATKO") +# print(tematko_object.id) +# odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu +# print(odkazy) +# cisla = [] # List tuplů (nazev cisla, list odkazů) +# vcisle = [] +# cislo = None +# for odkaz in odkazy: +# if odkaz[1] == 0: +# if cislo != None: +# cisla.append((cislo, vcisle)) +# cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()) +# vcisle = [] +# else: +# print(odkaz[0].getOdkaz()) +# vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())) +# if cislo != None: +# cisla.append((cislo, vcisle)) +# +# print(cisla) +# tematka.append({ +# "kod" : tematko_object.kod, +# "nazev" : tematko_object.nazev, +# "abstrakt" : tematko_object.abstrakt, +# "obrazek": tematko_object.obrazek, +# "cisla" : cisla +# }) +# return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik}) +# #def ZadaniAktualniVysledkovkaView(request): # nastaveni = get_object_or_404(Nastaveni) From 7cfb2c414e18bc16acbc671c37d4fa6cf154161b Mon Sep 17 00:00:00 2001 From: "Tomas \"Jethro\" Pokorny" Date: Thu, 19 Mar 2020 00:59:31 +0100 Subject: [PATCH 13/15] seminar | Pridan OtisknuteReseniNode, zakomentovany stare views. --- seminar/migrations/0078_otistenereseninode.py | 27 +++++++++++++++++++ seminar/models.py | 20 ++++++++++++++ seminar/urls.py | 8 +++--- 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 seminar/migrations/0078_otistenereseninode.py diff --git a/seminar/migrations/0078_otistenereseninode.py b/seminar/migrations/0078_otistenereseninode.py new file mode 100644 index 00000000..2f426a17 --- /dev/null +++ b/seminar/migrations/0078_otistenereseninode.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2.9 on 2020-03-18 23:59 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0077_auto_20200318_2146'), + ] + + operations = [ + migrations.CreateModel( + name='OtisteneReseniNode', + fields=[ + ('treenode_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='seminar.TreeNode')), + ('reseni', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='seminar.Reseni', verbose_name='reseni')), + ], + options={ + 'verbose_name': 'Otištěné řešení (Node)', + 'verbose_name_plural': 'Otištěná řešení (Node)', + 'db_table': 'seminar_nodes_otistene_reseni', + }, + bases=('seminar.treenode',), + ), + ] diff --git a/seminar/models.py b/seminar/models.py index 25e4130d..82b09944 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -1474,6 +1474,26 @@ class CastNode(TreeNode): nadpis = models.CharField('Nadpis', max_length=100, help_text = 'Nadpis podvěšené části obsahu') + def aktualizuj_nazev(self): + self.nazev = "CastNode: "+str(self.nadpis) + + def getOdkazStr(self): + return str(self.nadpis) + +class OtisteneReseniNode(TreeNode): + class Meta: + db_table = 'seminar_nodes_otistene_reseni' + verbose_name = 'Otištěné řešení (Node)' + verbose_name_plural = 'Otištěná řešení (Node)' + reseni = models.ForeignKey(Reseni, + on_delete=models.PROTECT, + verbose_name = 'reseni') + + def aktualizuj_nazev(self): + self.nazev = "OtisteneReseniNode: "+str(self.reseni) + + def getOdkazStr(self): + return str(self.reseni) ## FIXME: Logiku přesunout do views. #class VysledkyBase(SeminarModelBase): diff --git a/seminar/urls.py b/seminar/urls.py index 002170c4..4ec060ce 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -8,8 +8,8 @@ from django.contrib.auth import views as auth_views staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ - path('aktualni/temata/', views.TemataRozcestnikView), - path('/t/', views.TematkoView), +# path('aktualni/temata/', views.TemataRozcestnikView), +# path('/t/', views.TematkoView), # REDIRECTy path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), @@ -60,8 +60,8 @@ urlpatterns = [ ), # Zadani - path('zadani/aktualni/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), - path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'), +# path('zadani/aktualni/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), +# path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'), #path('zadani/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'), path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), From db5f0fd0c57837c88abe739f91a252c0af0e055a Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Thu, 19 Mar 2020 01:17:09 +0100 Subject: [PATCH 14/15] TreeLib: Swap left and right --- seminar/treelib.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index f890868b..a64c86d9 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -181,10 +181,44 @@ def create_node_before(some, arguments, but, i, dont, know, which, yet): def swap(node, other): raise NotImplementedError("YAGNI (You aren't gonna need it).") -def swap_pred(node): +# Exception, kterou některé metody při špatném použití mohou házet +# Hlavní důvod je možnost informovat o selhání, aby se příslušný problém dal zobrazit na frontendu, +class TreeLibError(RuntimeError): pass + +def swap_pred(node): + if node is None: + raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.") + pred = safe_pred(node) + if pred is None: + raise TreeLibError("Nelze posunout vlevo, není tam žádný další uzel.") + pre_pred = safe_pred(pred) + succ = node.succ + + if pre_pred is not None: + pre_pred.succ = node + pre_pred.save() + node.succ = pred + node.save() + pred.succ = succ + pred.save() + def swap_succ(node): - pass + if node is None: + raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.") + succ = node.succ + if succ is None: + raise TreeLibError("Nelze posunout vpravo, není tam žádný další uzel") + pred = safe_pred(node) + post_succ = succ.succ + + if pred is not None: + pred.succ = succ + pred.save() + succ.succ = node + succ.save() + node.succ = post_succ + node.save() # Rotace stromu # Dokumentace viz wiki: From c1e107c89e9ea193918c60c150d07a27f41d9e7f Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Thu, 19 Mar 2020 01:24:51 +0100 Subject: [PATCH 15/15] Treelib: create_node_before --- seminar/treelib.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/seminar/treelib.py b/seminar/treelib.py index a64c86d9..26b77d1d 100644 --- a/seminar/treelib.py +++ b/seminar/treelib.py @@ -173,9 +173,20 @@ def create_child(parent, type, **kwargs): new_node.succ = orig_child new_node.save() -def create_node_before(some, arguments, but, i, dont, know, which, yet): - pass - # Tohle bude hell. +def create_node_before(successor, type, **kwargs): + if safe_pred(successor) is not None: + # Easy: přidáme za předchůdce + create_node_after(successor.prev, type, **kwargs) + # Nemáme předchůdce, jsme tedy první z bratrů. Máme otce? + if safe_father_of_first(successor) is not None: + # Ano -> Easy: vyrobíme nového potomka + # NOTE: Tohle je možná trošku abuse implementace výše, ale to nevadí moc... + create_child(successor.father_of_first, type, **kwargs) + # Teď už easy: Jsme sirotci, takže se vyrobíme a našeho následníka si přidáme jako succ + new = type.objects.create(**kwargs) + new.succ = successor + new.save() + # ValueError, pokud je (aspoň) jeden parametr None def swap(node, other):