Merge pull request 'Upgrade odevzdavatka' (!30) from upgrade_odevzdavatka into master
Reviewed-on: #30
This commit is contained in:
commit
0528dbbb9c
15 changed files with 205 additions and 49 deletions
|
@ -70,23 +70,17 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer
|
|||
class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView):
|
||||
""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """
|
||||
def get_queryset(self):
|
||||
nastaveni = get_object_or_404(m.Nastaveni)
|
||||
rocnik = nastaveni.aktualni_rocnik
|
||||
# Od tohoto místa dál jsem zkoušel spoustu variací podle https://django-polymorphic.readthedocs.io/en/stable/advanced.html
|
||||
temaQ = Q(Tema___rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
|
||||
ulohaQ = Q(Uloha___cislo_zadani__rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
|
||||
clanekQ = Q(Clanek___cislo__rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
|
||||
qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ)
|
||||
#print(temata, ulohy, clanky)
|
||||
#ulohy.union(temata, all=True)
|
||||
#print(ulohy)
|
||||
#ulohy.union(clanky, all=True)
|
||||
#print(ulohy)
|
||||
#qs = ulohy
|
||||
print(qs)
|
||||
qs = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY)
|
||||
if self.q:
|
||||
qs = qs.filter(
|
||||
Q(nazev__icontains=self.q))
|
||||
|
||||
nadproblem_id = int(self.forwarded.get("nadproblem_id", -1))
|
||||
if nadproblem_id != -1:
|
||||
# Seřadíme tak, aby ty s nadproblem==None byly dole (větší motivace tam naklikat konkrétní úlohy) a pak nějak rozumně.
|
||||
# Tohle je řazení pro odevzdávátko, kde je definován nadproblém, proto je to v tomto ifu. (Jinde si to netroufám řadit)
|
||||
qs = qs.order_by("nadproblem", "kod", "nazev")
|
||||
qs = list(filter(lambda problem: problem.hlavni_problem.id == nadproblem_id, qs))
|
||||
return qs
|
||||
|
||||
class ProblemAutocomplete(autocomplete.Select2QuerySetView):
|
||||
|
|
|
@ -437,7 +437,7 @@
|
|||
"insitetree": true,
|
||||
"parent": 21,
|
||||
"sort_order": 36,
|
||||
"title": "Poslat řešení",
|
||||
"title": "Nahrát řešení",
|
||||
"tree": 1,
|
||||
"url": "seminar_nahraj_reseni",
|
||||
"urlaspattern": true
|
||||
|
@ -719,7 +719,7 @@
|
|||
"insitetree": true,
|
||||
"parent": 21,
|
||||
"sort_order": 36,
|
||||
"title": "Nahrát řešení",
|
||||
"title": "Vložit řešení",
|
||||
"tree": 1,
|
||||
"url": "seminar_vloz_reseni",
|
||||
"urlaspattern": true
|
||||
|
@ -1026,6 +1026,36 @@
|
|||
"model": "sitetree.treeitem",
|
||||
"pk": 51
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"access_guest": false,
|
||||
"access_loggedin": false,
|
||||
"access_perm_type": 1,
|
||||
"access_permissions": [
|
||||
[
|
||||
"resitel",
|
||||
"auth",
|
||||
"user"
|
||||
]
|
||||
],
|
||||
"access_restricted": true,
|
||||
"alias": null,
|
||||
"description": "",
|
||||
"hidden": false,
|
||||
"hint": "",
|
||||
"inbreadcrumbs": true,
|
||||
"inmenu": true,
|
||||
"insitetree": true,
|
||||
"parent": 23,
|
||||
"sort_order": 52,
|
||||
"title": "Nahrát řešení k nadproblému {{nadproblem_id}}",
|
||||
"tree": 1,
|
||||
"url": "seminar_nahraj_reseni nadproblem_id",
|
||||
"urlaspattern": true
|
||||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"pk": 52
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"access_guest": false,
|
||||
|
@ -1041,13 +1071,13 @@
|
|||
"inmenu": true,
|
||||
"insitetree": true,
|
||||
"parent": 28,
|
||||
"sort_order": 52,
|
||||
"sort_order": 53,
|
||||
"title": "Přidat PDF",
|
||||
"tree": 1,
|
||||
"url": "/admin/korektury/korekturovanepdf/add/",
|
||||
"urlaspattern": false
|
||||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"pk": 52
|
||||
"pk": 53
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -28,7 +28,7 @@ Generuje se za pomocí::
|
|||
|
||||
nebo (v případě meníčka)::
|
||||
|
||||
./manage.py dumpdata sitetree --natrual-foreign > data/sitetree_new.json
|
||||
./manage.py dumpdata sitetree --natural-foreign > data/sitetree_new.json
|
||||
./fix_json.py data/sitetree_new.json data/sitetree.json
|
||||
|
||||
deploy_v2
|
||||
|
|
|
@ -1260,3 +1260,22 @@ label[for=id_skola] {
|
|||
.bodovani>input {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
|
||||
/* Select2 používaný hlavně multiple selectem. Přidání checkboxů a změna barvy. */
|
||||
/* Podle https://stackoverflow.com/a/48290544 */
|
||||
/* U autocomplete.ModelSelect2Multiple vyžaduje 'data-dropdown-css-class': 's2m-se-zaskrtavatky' */
|
||||
.s2m-se-zaskrtavatky .select2-results__option[aria-selected=true]:before {
|
||||
content: '☑ ';
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
|
||||
.s2m-se-zaskrtavatky .select2-results__option[aria-selected=false]:before {
|
||||
content: '◻ ';
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
|
||||
/* Oranžové zvýraznění v Select2 */
|
||||
.select2-results__option--highlighted {
|
||||
background-color: #e84e10 !important;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ Obsahuje vše, co se týká odevzdávání (+ nahrávání) a opravování řeš
|
|||
Slovníček:
|
||||
Moje řešení = Přehled řešení = Řešení, která odevzdal aktuálního uživatel sám.
|
||||
Došlá řešení = Tabulka + seznam + detail + ... = Řešení, která poslal někdo jiný.
|
||||
Poslat řešení = Odevdat mé řešení. (Tj. řešení se vztahem k aktuálnímu uživateli.)
|
||||
Nahrát řešení = Nahrání řešení bez vztahu k aktuálnímu uživateli.
|
||||
Nahrát řešení = Odevdat mé řešení. (Tj. řešení se vztahem k aktuálnímu uživateli.)
|
||||
Vlož řešení = Vložit řešení bez vztahu k aktuálnímu uživateli.
|
||||
|
||||
TODO: Místo vložit řešení v nahrávání a posílání řešení dát něco jiného?
|
||||
"""
|
||||
"""
|
||||
|
|
|
@ -29,6 +29,8 @@ class PosliReseniForm(forms.Form):
|
|||
attrs={
|
||||
'data-placeholder--id': '-1',
|
||||
'data-placeholder--text': '---',
|
||||
'data-close-on-select': 'false',
|
||||
'data-dropdown-css-class': 's2m-se-zaskrtavatky',
|
||||
'data-allow-clear': 'true'
|
||||
},
|
||||
),
|
||||
|
@ -43,6 +45,8 @@ class PosliReseniForm(forms.Form):
|
|||
url='autocomplete_resitel',
|
||||
attrs = {'data-placeholder--id': '-1',
|
||||
'data-placeholder--text' : '---',
|
||||
'data-close-on-select': 'false',
|
||||
'data-dropdown-css-class': 's2m-se-zaskrtavatky',
|
||||
'data-allow-clear': 'true'})
|
||||
)
|
||||
|
||||
|
@ -62,12 +66,6 @@ class PosliReseniForm(forms.Form):
|
|||
#poznamka = models.TextField('neveřejná poznámka', blank=True,
|
||||
# help_text='Neveřejná poznámka k řešení (plain text)')
|
||||
|
||||
#TODO body do cisla
|
||||
#TODO prilohy
|
||||
|
||||
##def __init__(self, *args, **kwargs):
|
||||
## super().__init__(*args, **kwargs)
|
||||
## #self.fields['favorite_color'] = forms.ChoiceField(choices=[(color.id, color.name) for color in Resitel.objects.all()])
|
||||
|
||||
class NahrajReseniForm(forms.ModelForm):
|
||||
class Meta:
|
||||
|
@ -80,23 +78,40 @@ class NahrajReseniForm(forms.ModelForm):
|
|||
url='autocomplete_problem_odevzdatelny',
|
||||
attrs = {'data-placeholder--id': '-1',
|
||||
'data-placeholder--text' : '---',
|
||||
'data-close-on-select': 'false',
|
||||
'data-dropdown-css-class': 's2m-se-zaskrtavatky',
|
||||
'data-allow-clear': 'true'},
|
||||
forward=["nadproblem_id"],
|
||||
),
|
||||
'resitele':
|
||||
autocomplete.ModelSelect2Multiple(
|
||||
url='autocomplete_resitel_public',
|
||||
attrs = {'data-placeholder--id': '-1',
|
||||
'data-placeholder--text' : '---',
|
||||
'data-close-on-select': 'false',
|
||||
'data-dropdown-css-class': 's2m-se-zaskrtavatky',
|
||||
'data-allow-clear': 'true'},
|
||||
)
|
||||
}
|
||||
|
||||
nadproblem_id = forms.IntegerField(required=False, disabled=True, widget=forms.HiddenInput())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# FIXME Z nějakého důvodu se do této třídy dostaneme i bez resitele
|
||||
if 'resitele' in self.fields:
|
||||
# FIXME Mnohem hezčí by to bylo u definice resitele výše, ale nepodařilo se mi to.
|
||||
self.fields['resitele'].required = False
|
||||
self.fields['resitele'].label = "Další autoři"
|
||||
if 'problem' in self.fields:
|
||||
self.fields['problem'].label = "Všechny řešené problémy"
|
||||
|
||||
def clean_problem(self):
|
||||
problem = self.cleaned_data.get('problem')
|
||||
for p in problem:
|
||||
if p.stav != m.Problem.STAV_ZADANY:
|
||||
raise forms.ValidationError("Problém " + str(p) + " již nelze řešit!")
|
||||
return problem
|
||||
|
||||
ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni,
|
||||
form = NahrajReseniForm,
|
||||
|
|
|
@ -7,19 +7,20 @@
|
|||
{% block content %}
|
||||
<h1>
|
||||
{% block nadpis1a %}
|
||||
Vložit řešení
|
||||
Nahrát řešení
|
||||
{% endblock %}
|
||||
</h1>
|
||||
|
||||
<p style="text-align: justify">Když řešení různých témátek vložíš každé zvlášť, lépe se v nich vyznáme a třeba ti je i rychleji opravíme.</p>
|
||||
|
||||
<p>Pokud řešíte ve více lidech, je <strong>nutné</strong> přidat tyto lidi jako „Autory řešení“. V tomto poli se vyhledává podle přezdívek, které si lze nastavit v „Osobní údaje“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze <strong>jednou</strong> (ne každý sám).</p>
|
||||
|
||||
<form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' %}" method="post" onsubmit="return zkontroluj_prilohy();">
|
||||
<form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' nadproblem_id %}" method="post" onsubmit="return zkontroluj_prilohy();">
|
||||
{% csrf_token %}
|
||||
<table class='form' id="reseni">
|
||||
<table class='form'>
|
||||
<tr>
|
||||
<td><label class="field-label field-required" for="tema">Téma:</label></td>
|
||||
<td><input id="tema" disabled="" type="text" value="{{ nadproblem }}"></td>
|
||||
</tr>
|
||||
|
||||
{% with field=form.problem %}
|
||||
<tr>
|
||||
{% for field in form %}
|
||||
<td>
|
||||
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
|
||||
{{ field.label }}:
|
||||
|
@ -28,15 +29,54 @@
|
|||
<td>
|
||||
{{ field }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
{% if field.errors %}
|
||||
<tr>
|
||||
<td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% endwith %}
|
||||
</table>
|
||||
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
|
||||
<hr>
|
||||
<h4>Spolupráce s dalšími řešiteli</h4>
|
||||
|
||||
<p>Pokud řešíte ve více lidech, je <strong>potřeba</strong> přidat tyto lidi jako „Další autory“. V tomto poli se vyhledává podle přezdívek, které si lze nastavit v „Osobních údajích“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze <strong>jednou</strong> (ne každý sám).</p>
|
||||
|
||||
<table class='form'>
|
||||
{% with field=form.resitele %}
|
||||
<tr>
|
||||
<td>
|
||||
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
|
||||
{{ field.label }}:
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
{{ field }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% if field.errors %}
|
||||
<tr>
|
||||
<td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% endwith %}
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
|
||||
{% include "odevzdavatko/prilohy.html" %}
|
||||
|
||||
{{form.non_field_errors}}
|
||||
|
||||
<hr>
|
||||
<h4>Odevzdat řešení</h4>
|
||||
<input type="submit" value="Odevzdat">
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% block nadpis1a %}
|
||||
Nahrát řešení
|
||||
{% endblock %}
|
||||
</h1>
|
||||
|
||||
<h4>Seznam témat k odevzdání</h4>
|
||||
|
||||
<ul>
|
||||
{% for problem in object_list %}
|
||||
<li><a href="{% url 'seminar_nahraj_reseni' problem.id %}">{{ problem }}</a></li>
|
||||
{% empty %}
|
||||
<li>Nelze nic odevzdávat.</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
<h4>Soubory s řešením</h4>
|
||||
|
||||
<p style="text-align: justify">Maximální součet velikostí příloh je cca 49 MB. Pokud je to možné a dává to smysl, pošli nám prosím své řešení ve formátu PDF, ostatní formáty nemusíme umět otevřít.</p>
|
||||
<p style="text-align: justify">Pokud svůj soubor rozumně pojmenuješ, urychlíš opravování a předejdeš tomu, že si nějakého tvého řešení nevšimneme. Například z <code>img_250921_101205.pdf</code> nepoznáme, kterou úlohu jsi odevzdal, zato <code>uloha_3.pdf</code> nebo <code>tema_1.pdf</code>, to už je něco jiného. Případně můžeš využít i poznámku řešitele.</p>
|
||||
<p style="text-align: justify">Pokud je to možné a dává to smysl (tj. není to třeba kód nebo doprovodný obrázek), pošli nám prosím své řešení ve formátu <strong>PDF</strong>, ostatní formáty nemusíme umět otevřít.</p>
|
||||
<p style="text-align: justify">Pokud svůj soubor <strong>rozumně pojmenuješ</strong>, urychlíš opravování a předejdeš tomu, že si nějakého tvého řešení nevšimneme. Například z <code>img_250921_101205.pdf</code> nepoznáme, kterou úlohu jsi odevzdal, zato <code>uloha_3.pdf</code> nebo <code>tema_1.pdf</code>, to už je něco jiného. Případně můžeš využít i poznámku řešitele.</p>
|
||||
<p style="text-align: justify">Maximální součet velikostí příloh je cca <strong>49 MB</strong>.</p>
|
||||
|
||||
<div id="form_set">
|
||||
{% for form in prilohy.forms %}
|
||||
|
|
|
@ -19,8 +19,9 @@ from seminar.utils import org_required, resitel_required, viewMethodSwitch, \
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('org/add_solution', org_required(views.PosliReseniView.as_view()), name='seminar_vloz_reseni'),
|
||||
path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
|
||||
path('org/add_solution', org_required(views.VlozReseniView.as_view()), name='seminar_vloz_reseni'),
|
||||
path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniRozcestnikTematekView.as_view()), name='seminar_nahraj_reseni'),
|
||||
path('resitel/nahraj_reseni/<int:nadproblem_id>/', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
|
||||
path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_reseni'),
|
||||
|
||||
path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
||||
|
|
|
@ -367,8 +367,8 @@ class SeznamAktualnichReseniView(SeznamReseniView):
|
|||
return qs
|
||||
|
||||
|
||||
class PosliReseniView(LoginRequiredMixin, FormView):
|
||||
template_name = 'odevzdavatko/posli_reseni.html'
|
||||
class VlozReseniView(LoginRequiredMixin, FormView):
|
||||
template_name = 'odevzdavatko/vloz_reseni.html'
|
||||
form_class = f.PosliReseniForm
|
||||
|
||||
def form_valid(self, form):
|
||||
|
@ -399,12 +399,27 @@ class PosliReseniView(LoginRequiredMixin, FormView):
|
|||
return data
|
||||
|
||||
|
||||
class NahrajReseniRozcestnikTematekView(LoginRequiredMixin, ListView):
|
||||
model = m.Problem
|
||||
template_name = 'odevzdavatko/nahraj_reseni_nadproblem.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(stav=m.Problem.STAV_ZADANY, nadproblem__isnull=True)
|
||||
|
||||
|
||||
class NahrajReseniView(LoginRequiredMixin, CreateView):
|
||||
model = m.Reseni
|
||||
template_name = 'odevzdavatko/nahraj_reseni.html'
|
||||
form_class = f.NahrajReseniForm
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
# Zaříznutí nezadaných problémů
|
||||
nadproblem_id = self.kwargs["nadproblem_id"]
|
||||
self.nadproblem = get_object_or_404(m.Problem, id=nadproblem_id)
|
||||
if self.nadproblem.stav != "zadany":
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
# Zaříznutí starých řešitelů:
|
||||
# FIXME: Je to tady dost naprasené, mělo by to asi být jinde…
|
||||
osoba = m.Osoba.objects.get(user=self.request.user)
|
||||
|
@ -417,12 +432,23 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
|
|||
})
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_initial(self):
|
||||
nadproblem_id = self.nadproblem.id
|
||||
return {
|
||||
"nadproblem_id": nadproblem_id,
|
||||
"problem": [] if self.nadproblem.podproblem.filter(stav=m.Problem.STAV_ZADANY).exists() else nadproblem_id
|
||||
|
||||
}
|
||||
|
||||
def get_context_data(self,**kwargs):
|
||||
data = super().get_context_data(**kwargs)
|
||||
if self.request.POST:
|
||||
data['prilohy'] = f.ReseniSPrilohamiFormSet(self.request.POST,self.request.FILES)
|
||||
else:
|
||||
data['prilohy'] = f.ReseniSPrilohamiFormSet()
|
||||
|
||||
data["nadproblem_id"] = self.nadproblem.id
|
||||
data["nadproblem"] = get_object_or_404(m.Problem, id=self.nadproblem.id)
|
||||
return data
|
||||
|
||||
# FIXME prepsat tak, aby form_valid se volalo jen tehdy, kdyz je form i formset validni
|
||||
|
@ -474,4 +500,8 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
|
|||
to=list(prijemci),
|
||||
).send()
|
||||
|
||||
return formularOKView(self.request, text='Řešení úspěšně odevzdáno')
|
||||
return formularOKView(
|
||||
self.request,
|
||||
text='Řešení úspěšně odevzdáno',
|
||||
dalsi_odkazy=[("Odevzdat další řešení", reverse("seminar_nahraj_reseni"))],
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<a href="{% url 'logout' %}">Odhlásit se</a><br>
|
||||
<a href="{% url 'seminar_resitel_edit' %}">Upravit údaje</a><br>
|
||||
<a href="{% url 'seminar_nahraj_reseni' %}">Poslat řešení</a><br>
|
||||
<a href="{% url 'seminar_nahraj_reseni' %}">Nahrát řešení</a><br>
|
||||
<a href="{% url 'seminar_resitel_odevzdana_reseni' %}">Již odevzdaná řešení</a><br>
|
||||
|
||||
|
||||
|
|
|
@ -173,7 +173,11 @@ def resitelEditView(request):
|
|||
msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
|
||||
resitel_edit.save()
|
||||
osoba_edit.save()
|
||||
return formularOKView(request, text=f'Údaje byly úspěšně uloženy. <a href="{reverse("profil")}">Vrátit se zpět na profil.</a>')
|
||||
return formularOKView(
|
||||
request,
|
||||
text='Údaje byly úspěšně uloženy.',
|
||||
dalsi_odkazy=[("Vrátit se zpět na profil", reverse("profil"))],
|
||||
)
|
||||
|
||||
return render(request, 'personalni/udaje/edit.html', {'form': form})
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ from django.conf import settings
|
|||
import unicodedata
|
||||
import logging
|
||||
import time
|
||||
from collections.abc import Sequence
|
||||
|
||||
from seminar.utils import aktivniResitele
|
||||
|
||||
|
@ -677,9 +678,9 @@ def StavDatabazeView(request):
|
|||
|
||||
|
||||
# Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí)
|
||||
def formularOKView(request, text=''):
|
||||
def formularOKView(request, text='', dalsi_odkazy: Sequence[tuple[str, str]] = ()):
|
||||
template_name = 'seminar/formular_ok.html'
|
||||
odkazy = [
|
||||
odkazy = list(dalsi_odkazy) + [
|
||||
# (Text, odkaz)
|
||||
('Vrátit se na titulní stránku', reverse('titulni_strana')),
|
||||
('Zobrazit aktuální zadání', reverse('seminar_aktualni_zadani')),
|
||||
|
|
Loading…
Reference in a new issue