Přednášky #87
|  | @ -10,7 +10,7 @@ from soustredeni.models import Soustredeni | |||
| 
 | ||||
| class Seznam_PrednaskaInline(admin.TabularInline): | ||||
| 	""" | ||||
| 		Pomůcka pro :py:class:`prednasky.admin.SeznamAdmin` zobrazující hezky :py:class:`Přednášky <prednasky.models.Prednaska>` | ||||
| 		:py:class:`Inline <django.contrib.admin.TabularInline>` pro :py:class:`prednasky.admin.SeznamAdmin` zobrazující :py:class:`Přednášky <prednasky.models.Prednaska>` | ||||
| 		v adminu :py:class:`Seznamu <prednasky.models.Seznam>`. | ||||
| 	""" | ||||
| 
				
				zelvuska marked this conversation as resolved
				
			 | ||||
| 	model = Prednaska.seznamy.through | ||||
|  | @ -60,7 +60,7 @@ class Seznam_PrednaskaInline(admin.TabularInline): | |||
| 
 | ||||
| class Seznam_ZnalostInline(admin.TabularInline): | ||||
| 	""" | ||||
| 		Pomůcka pro :py:class:`prednasky.admin.SeznamAdmin` zobrazující hezky :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 		:py:class:`Inline <django.contrib.admin.TabularInline>` pro :py:class:`prednasky.admin.SeznamAdmin` zobrazující :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 		v adminu :py:class:`Seznamu <prednasky.models.Seznam>`. | ||||
| 	""" | ||||
| 	model = Znalost.seznamy.through | ||||
|  | @ -97,7 +97,7 @@ admin.site.register(Seznam, SeznamAdmin) | |||
| 
 | ||||
| 
 | ||||
| class PrednaskaAdmin(VersionAdmin): | ||||
| 	""" Admin pro :py:class:`Přednášku <prednasky.models.Prednaska> """ | ||||
| 	""" Admin pro :py:class:`Přednášku <prednasky.models.Prednaska>` """ | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						ledoian
						commented  
 ``>` `` | ||||
| 	list_display = ['nazev', 'org', 'obor'] | ||||
| 	list_filter = ['org', 'obor'] | ||||
| 	search_fields = ['nazev'] | ||||
|  | @ -138,7 +138,7 @@ admin.site.register(Prednaska, PrednaskaAdmin) | |||
| 
 | ||||
| class ZnalostAdmin(PrednaskaAdmin): # Trochu hack, ať nemusím vypisovat všechno znovu | ||||
| 	""" | ||||
| 		Admin pro :py:class:`Znalost <prednasky.models.Znalost> | ||||
| 		Admin pro :py:class:`Znalost <prednasky.models.Znalost>` | ||||
| 		TODO předělat, aby nedědila z :py:class:`prednasky.admin.PrednaskaAdmin`, ale společné věci byly zvlášť | ||||
| 	""" | ||||
| 
				
				zelvuska marked this conversation as resolved
				
			 
				
					
						ledoian
						commented  Za  Za ``Znalost>`` má být `` ` ``, před ``prednasky.admin.PrednaskaAdmin`` má taky být `` ` ``. 
				
					
						zelvuska
						commented  Před PrednskaAdmin je… Před PrednskaAdmin je… | ||||
| 	list_display = ("__str__",) | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from django import forms | |||
| from .models import Hlasovani, HlasovaniOZnalostech | ||||
| 
 | ||||
| class HlasovaniPrednaskaForm(forms.Form): | ||||
| 	""" :py:class:`Formulář <django.forms.Form>` pro pro :py:class:`Hlasování <prednasky.models.Hlasovani>` o jedné :py:class:`Přednášce <prednasky.models.Prednaska>` | ||||
| 	""" :py:class:`Formulář <django.forms.Form>` pro :py:class:`Hlasování <prednasky.models.Hlasovani>` o jedné :py:class:`Přednášce <prednasky.models.Prednaska>` | ||||
| 	(neobsahuje téměř nic, většina se musí doplnit jiným způsobem) | ||||
| 	""" | ||||
| 
 | ||||
|  | @ -17,7 +17,7 @@ class HlasovaniPrednaskaForm(forms.Form): | |||
| HlasovaniPrednaskaFormSet = forms.formset_factory(HlasovaniPrednaskaForm, extra=0) | ||||
| 
 | ||||
| class HlasovaniZnalostiForm(forms.Form): | ||||
| 	""" :py:class:`Formulář <django.forms.Form>` pro pro :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>` o jedné :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 	""" :py:class:`Formulář <django.forms.Form>` pro :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>` o jedné :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						ledoian
						commented  Jsem pro smazání jednoho  Jsem pro smazání jednoho `pro` ☺ | ||||
| 	(neobsahuje téměř nic, většina se musí doplnit jiným způsobem) | ||||
| 	""" | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										20
									
								
								prednasky/migrations/0023_hlasovani_ucastnik_osoba.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,20 @@ | |||
| # Generated by Django 4.2.16 on 2025-02-19 17:31 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('personalni', '0019_rename_upozorneni_resitel_upozornovat_na_opravy_reseni'), | ||||
|         ('prednasky', '0022_preklep_u_odpovedi_hlasovanioznalostech'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='hlasovani', | ||||
|             name='ucastnik_osoba', | ||||
|             field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='personalni.osoba'), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -6,7 +6,7 @@ from personalni.models import Organizator, Osoba | |||
| 
 | ||||
| class Seznam(models.Model): | ||||
| 	""" | ||||
| 		Spojuje :py:class:`Přednášky <prednasky.models.Prednaska>` | ||||
| 		Spojuje :py:class:`Přednášky <prednasky.models.Prednaska>` a :py:class:`Znalosti <prednasky.models.Znalost> | ||||
| 		se :py:class:`Soustředěními <soustredeni.models.Soustredeni>`, | ||||
| 		kde by mohly zaznít, nebo zazní/zazněly. | ||||
| 	""" | ||||
|  | @ -19,8 +19,8 @@ class Seznam(models.Model): | |||
| 
 | ||||
| 	class Stav(models.IntegerChoices): | ||||
| 		""" Stav seznamu přednášek (NAVRH se používá k hlasování viz :py:func:`daný view <prednasky.views.newPrednaska>`). """ | ||||
| 		NAVRH = 1, "Návrh" | ||||
| 		BUDE = 2, "Bude" | ||||
| 		NAVRH = 1, "Návrh" #: odpovídá před-soustřeďkové představě o tom, jaké přednášky dělat (dá se o nich třeba hlasovat ap.) | ||||
| 		BUDE = 2, "Bude" #: odpovídá definitivní představě o tom, co bude/bylo a dá se porovnávat s novými návrhy | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						ledoian
						commented  Umíme dokumentovat i přímo jednotlivé možnosti? Přijde mi, že si to tady říká o rozepsání, že  (also: za mě sémanticky View využívá Model, takže odkazovat to, jak funguje Model podle použití ve View je kinda divné…) Umíme dokumentovat i přímo jednotlivé možnosti? Přijde mi, že si to tady říká o rozepsání, že `NAVRH` odpovídá před-soustřeďkové představě o tom, jaké přednášky dělat (dá se o nich třeba hlasovat ap.), zatímco `BUDE` odpovídá definitivní představě o tom, co bude/bylo a dá se porovnávat s novými návrhy (třeba aby stejná přednáška nebyla na pěti po sobě jdoucích sousech…) 
(also: za mě sémanticky View využívá Model, takže odkazovat to, jak funguje Model podle použití ve View je kinda divné…) | ||||
| 
 | ||||
| 	id = models.AutoField(primary_key=True) | ||||
| 	soustredeni = models.ForeignKey(Soustredeni, null=True, default=None, on_delete=models.PROTECT) | ||||
|  | @ -88,6 +88,7 @@ class Hlasovani(models.Model): | |||
| 	#: že všechna předchozí hlasování zde mají náhodný string…) | ||||
| 	#: TODO Změnit to na Osobu* | ||||
| 	ucastnik = models.CharField("Účastník", max_length=100) | ||||
| 
				
				zelvuska marked this conversation as resolved
				
			 
				
					
						ledoian
						commented  Hmm, existuje čisté a praktické řešení. To čisté a datazachovávající je mít pro osobu nový FK (s  Praktické řešení je se na původní hlasy vykašlat, buď je dropnout úplně, nebo jim nastavit Osobu na NULL a pak sice nepůjde dohledat, kdo hlasoval k čemu, ale aspoň informace o zájmu v každém seznamu přežije. (Myslím, že ta druhá varianta vyžaduje zbytečně moc hackování třeba exportů, takže za to nestojí…) Hmm, existuje čisté a praktické řešení. To čisté a datazachovávající je mít pro osobu nový FK (s `null=True, blank=False`) a mít stará řešení se string-účastníkem a nová s Osobou.
Praktické řešení je se na původní hlasy vykašlat, buď je dropnout úplně, nebo jim nastavit Osobu na NULL a pak sice nepůjde dohledat, kdo hlasoval k čemu, ale aspoň informace o zájmu v každém seznamu přežije. (Myslím, že ta druhá varianta vyžaduje zbytečně moc hackování třeba exportů, takže za to nestojí…) 
				
					
						ledoian
						commented  Also: tu Osobu (s null=True) si IMHO chceme ukládat už teď, ať pak můžeme zmigrovat a nechybí nám data… (původní hlasovátko ještě nevědělo nic o účastnických uživatelích/osobách…) Also: tu Osobu (s null=True) si IMHO chceme ukládat už teď, ať pak můžeme zmigrovat a nechybí nám data… (původní hlasovátko ještě nevědělo nic o účastnických uživatelích/osobách…) | ||||
| 	ucastnik_osoba = models.ForeignKey(Osoba, on_delete=models.CASCADE, blank=False, null=True) | ||||
| 	seznam = models.ForeignKey(Seznam, null=True, on_delete=models.SET_NULL) | ||||
| 
 | ||||
| 	def __str__(self): | ||||
|  | @ -98,6 +99,9 @@ class Znalost(models.Model): | |||
| 	""" | ||||
| 		Reprezentuje znalost, na kterou se můžeme účastníka ptát (nechat je hlasovat). | ||||
| 		(Viz :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>`.) | ||||
| 
 | ||||
| 		(V podstatě :py:class:`Přednáška <prednasky.models.Prednaska>, jen neobsahuje | ||||
| 		tolik detailů a v hlasování má jiné odpovědi.) | ||||
| 	""" | ||||
| 	class Meta: | ||||
| 		db_table = "prednasky_znalost" | ||||
|  | @ -117,6 +121,9 @@ class HlasovaniOZnalostech(models.Model): | |||
| 		Reprezentuje hlasování jednoho účastníka | ||||
| 		o jedné :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 		v jednom :py:class:`Seznamu <prednasky.models.Seznam>` (účastníkův pohled se totiž mezi sousy změnit) | ||||
| 
 | ||||
| 		(V podstatě totéž, co :py:class:`Hlasování <prednasky.models.Hlasovani>`, jen má jiné komentáře | ||||
| 		u odpovědí a místo přednášky odkazuje na znalost.) | ||||
| 	""" | ||||
| 	class Odpoved(models.IntegerChoices): | ||||
| 		""" Na kolik danou znalost účastník ovládá v daném Hlasování (větší číslo = víc zná) """ | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| <p>Obtížnost 1 je nejlehčí, 3 nejtěžší.</p> | ||||
|   {{ form_set_prednasky.management_form }} | ||||
|   {% for f, p in formy_a_prednasky %} | ||||
|     <div class="hlasovani-prednaska"> | ||||
|     <h4>{{p.nazev}} ({{p.org}})</h4> | ||||
|     <p class="textprednasky">{{p.anotace | linebreaksbr}}</p> | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						ledoian
						commented  Navrhuji mít kolem každého bloku hlasování aspoň dummy  Navrhuji mít kolem každého bloku hlasování aspoň dummy `<div>`, ať se kdyžtak dají různě popřeskládat (kupř. nějakým flexem na ultraširokém monitoru vedle sebe, idk) a nehrozí někde rozbití CSS. (Případně ať si můžu nahackovat dodatečná CSS :-D) | ||||
|     <label>Obor: </label> {{p.obor}}<br> | ||||
|  | @ -22,17 +23,20 @@ | |||
|     <br> | ||||
|     {{ f }} | ||||
|     <br> | ||||
|     </div> | ||||
|   {% empty %} | ||||
|     Nejsou žádné přednášky o kterých by šlo hlasovat. | ||||
|   {% endfor %} | ||||
| 
 | ||||
|   {{ form_set_znalosti.management_form }} | ||||
|   {% for f, z in formy_a_znalosti %} | ||||
|     <div class="hlasovani-znalost"> | ||||
|     {% if forloop.first %}<hr/><h3>Jak moc znáš následující?</h3>{% endif %} | ||||
|     <h4>{{z.nazev}}</h4> | ||||
|     <p class="textznalosti">{{z.text | linebreaksbr}}</p> | ||||
|     {{ f }} | ||||
|     <br> | ||||
|     </div> | ||||
|   {% endfor %} | ||||
|   <input type="submit" value="Odeslat"/> | ||||
| </form> | ||||
|  |  | |||
|  | @ -2,19 +2,19 @@ | |||
| 
 | ||||
| {% block content %} | ||||
|   <h1>{% block nadpis1a %} | ||||
| 	  Hlasování o přednáškách | ||||
| 	  Výsledky hlasování o přednáškách | ||||
| 	  {% endblock %}</h1> | ||||
|   {# Projdi vsechny seznamy #} | ||||
|   <div class="mam-org-only"> | ||||
|   <ul> | ||||
|   {% for seznam in object_list %} | ||||
|     <li> | ||||
|     {% if seznam.stav == 1 %} {# STAV_NAHRH = 1 #}  | ||||
|         <a href="/prednasky/seznam_prednasek/{{seznam.id}}">Návrh přednášek na soustředění {{seznam.soustredeni.misto}} </a> | ||||
|     {% if seznam.stav == seznam.Stav.NAVRH %} | ||||
|       Návrh přednášek na soustředění {{seznam.soustredeni.misto}} | ||||
|     {% else %} | ||||
|         <a href="/prednasky/seznam_prednasek/{{seznam.id}}">Seznam přednášek na soustředění {{seznam.soustredeni.misto}} </a> | ||||
|       Seznam přednášek na soustředění {{seznam.soustredeni.misto}} | ||||
|     {% endif %} | ||||
|     <a href="/prednasky/seznam_prednasek/{{seznam.id}}/hlasovani.csv">Export</a> | ||||
|       (<a href='{% url "seznam-export-csv" seznam=seznam.id %}'>CSV</a>) | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						ledoian
						commented  
 `{% url … %}` | ||||
|     </li> | ||||
|   {% endfor %} | ||||
|   </ul> | ||||
|  |  | |||
|  | @ -12,19 +12,9 @@ urlpatterns = [ | |||
| 		'prednasky/metaseznam_prednasek', | ||||
| 		org_required(views.MetaSeznamListView.as_view()), | ||||
| 		name='metaseznam-list'), | ||||
| 	# path( | ||||
| 	# 	'prednasky/seznam_prednasek/<int:seznam>/export', | ||||
| 	# 	org_required(views.SeznamExportView), | ||||
| 	# 	name='seznam-export' | ||||
| 	# ), | ||||
| 	path( | ||||
| 		'prednasky/seznam_prednasek/<int:seznam>/hlasovani.csv', | ||||
| 		org_required(views.PrednaskyExportView), | ||||
| 		name='seznam-export-csv' | ||||
| 	), | ||||
| 	path( | ||||
| 		'prednasky/seznam_prednasek/<int:seznam>/', | ||||
| 		org_required(views.SeznamListView.as_view()), | ||||
| 		name='seznam-list' | ||||
| 	), | ||||
| ] | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ def newPrednaska(request: HttpRequest) -> HttpResponse: | |||
| 						prednaska=prednaska, | ||||
| 						body=form.cleaned_data['body'], | ||||
| 						ucastnik=ucastnik, | ||||
| 						ucastnik_osoba=osoba, | ||||
| 						seznam=seznam, | ||||
| 					) | ||||
| 
 | ||||
|  | @ -116,8 +117,8 @@ def newPrednaska(request: HttpRequest) -> HttpResponse: | |||
| 		'prednasky/base.html', | ||||
| 		{ | ||||
| 			'form_set_prednasky': form_set_prednasky, 'form_set_znalosti': form_set_znalosti, | ||||
| 			'formy_a_prednasky': zip(form_set_prednasky, prednasky), | ||||
| 			'formy_a_znalosti': zip(form_set_znalosti, znalosti), | ||||
| 			'formy_a_prednasky': list(zip(form_set_prednasky, prednasky)), | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						ledoian
						commented  Osobní preference: mít z toho „klasické“ datové typy (pole dvojic), ne  Osobní preference: mít z toho „klasické“ datové typy (pole dvojic), ne `zip` objekty, které se konzumují a nedají se proto cyklit opakovaně. (Až to někdo bude zkoušet, tak je imho velká šance, že mu to bude dělat blbosti a nebude chápat proč…) | ||||
| 			'formy_a_znalosti': list(zip(form_set_znalosti, znalosti)), | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
|  | @ -132,64 +133,6 @@ class MetaSeznamListView(generic.ListView): | |||
| 	template_name = 'prednasky/metaseznam_prednasek.html' | ||||
| 
 | ||||
| 
 | ||||
| class SeznamListView(generic.ListView): | ||||
| 	""" | ||||
| 		Náhled na to, kolik má která přednáška v :py:class:`Seznamu <prednasky.models.Seznam>` :py:class:`hlasů <prednasky.models.Hlasovani.Body>`. | ||||
| 		(Je otázka, zda tento View vůbec chceme. Pokud ano, hodilo by se do něj přidat i znalosti.) | ||||
| 	""" | ||||
| 	template_name = 'prednasky/seznam_prednasek.html' | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"]) | ||||
| 		prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by( | ||||
| 			'org__osoba__user__first_name', 'org__osoba__user__last_name' | ||||
| 		) | ||||
| 		return prednasky | ||||
| 
 | ||||
| 	# FIXME nahradit anotaci s filtrem po prechodu na Django 2.2 | ||||
| 	def get_context_data(self,**kwargs): | ||||
| 		context = super(SeznamListView, self).get_context_data(**kwargs) | ||||
| 
 | ||||
| 		# hlasovani se vztahuje k nejnovejsimu soustredeni | ||||
| 		sous = Soustredeni.objects.first() | ||||
| 		seznam = Seznam.objects.filter(soustredeni = sous, stav=Seznam.Stav.NAVRH).first() | ||||
| 	 | ||||
| 		for obj in self.object_list: | ||||
| 			hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body') | ||||
| 			obj.body = sum(map(lambda x: x.body,hlasovani_set)) | ||||
| 
 | ||||
| 		return context | ||||
| 
 | ||||
| 
 | ||||
| # def SeznamExportView(request, seznam): | ||||
| # 	"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" | ||||
| # 	# TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro | ||||
| # 	# lidi? | ||||
| # 	hlasovani = Hlasovani.objects.filter(seznam=seznam) | ||||
| # 	prednasky = Prednaska.objects.filter(seznamy=seznam) | ||||
| # 	orgove = set(p.org for p in prednasky) | ||||
| # 	ucastnici = set(h.ucastnik for h in hlasovani) | ||||
| # | ||||
| # 	for p in prednasky: | ||||
| # 		p.body = [] | ||||
| # 		for u in ucastnici: | ||||
| # 			try: | ||||
| # 				p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body) | ||||
| # 			except ObjectDoesNotExist: | ||||
| # 				# účastník nehlasoval | ||||
| # 				p.body.append("?") | ||||
| # | ||||
| # 	for h in hlasovani: | ||||
| # 		h.ucastnik = hash(h.ucastnik) | ||||
| # | ||||
| # 	return render( | ||||
| # 		request, | ||||
| # 		'prednasky/seznam_prednasek_export.txt', | ||||
| # 		{"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove}, | ||||
| # 		content_type="text/plain" | ||||
| # 	) | ||||
| 
 | ||||
| 
 | ||||
| def PrednaskyExportView(request: HttpRequest, seznam: int, **kwargs) -> HttpResponse: | ||||
| 	""" | ||||
| 		Vrátí všechna :py:class:`Hlasování <prednasky.models.Hlasovani>` | ||||
|  | @ -214,6 +157,8 @@ def PrednaskyExportView(request: HttpRequest, seznam: int, **kwargs) -> HttpResp | |||
| 	# A po inicializaci sloupců vyplníme tabulku | ||||
| 	table: [str, list[str|Prednaska|Znalost,]] = {} | ||||
| 
 | ||||
| 	errors = [] | ||||
| 
 | ||||
| 	for h in hlasovani: | ||||
| 		if h.ucastnik not in table: # Pokud jsme účastníka ještě neviděli, předgenerujeme si jeho řádek | ||||
| 			table[h.ucastnik] = [h.ucastnik] + ([""] * width) | ||||
|  | @ -221,7 +166,7 @@ def PrednaskyExportView(request: HttpRequest, seznam: int, **kwargs) -> HttpResp | |||
| 		if h.prednaska.id in prednasky_map: | ||||
| 			table[h.ucastnik][prednasky_map[h.prednaska.id]] = h.body | ||||
| 		else: | ||||
| 			pass # TODO Padat hlasitě? | ||||
| 			errors.append(f"Přednáška {h.prednaska.id} ({h.prednaska}) dostala od Účastníka {h.ucastnik} následující hodnocení: {h.body}") | ||||
| 
 | ||||
| 	for h in hlasovani_o_znalostech: | ||||
| 		ucastnik = str(h.ucastnik) + ' ' + str(h.ucastnik.id) # id, kvůli kolizi jmen | ||||
|  | @ -231,8 +176,10 @@ def PrednaskyExportView(request: HttpRequest, seznam: int, **kwargs) -> HttpResp | |||
| 		if h.znalost.id in znalosti_map: | ||||
| 			table[ucastnik][znalosti_map[h.znalost.id]] = h.odpoved | ||||
| 		else: | ||||
| 			pass # TODO Padat hlasitě? | ||||
| 			errors.append(f"Znalost {h.znalost.id} ({h.znalost}) dostala od Účastníka {h.ucastnik.id} následující odpověď: {h.odpoved}") | ||||
| 
 | ||||
| 	if len(errors) > 0: | ||||
| 		logger.error("Při exportování hlasování o přednáškách a znalostech se neexportovali hodnocení a přednášky (pravděpodobně se od hlasování vyškrtla nějaká znalost/přednáška ze seznamu):\n" + "\n".join(errors)) | ||||
| 
 | ||||
| 	response = HttpResponse(content_type="text/csv", charset="utf-8") | ||||
| 	response["Content-Disposition"] = 'attachment; filename="hlasovani.csv"' | ||||
|  |  | |||
Nechceš tomu prostě říkat Inline a odkázat dokumentaci Djanga rovnou? Přijde mi, že znalý stejně vidí, že to je Inline a neznalému „Pomůcka zobrazující hezky“ dá zbytečně málo informace.
Navrhuji „Inline pro … zobrazující …“
(i dál)