views: úprava počítání bodů odjakživa, počítání bodů za ročník také pomocí agregace. Smazání debug výpisů.
This commit is contained in:
		
							parent
							
								
									6cfde792c0
								
							
						
					
					
						commit
						f281d5f724
					
				
					 1 changed files with 98 additions and 56 deletions
				
			
		|  | @ -324,10 +324,16 @@ class ArchivView(generic.ListView): | |||
| 
 | ||||
| ### Výsledky | ||||
| 
 | ||||
| # ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník  | ||||
| # vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.), | ||||
| # podle toho, jak jdou za sebou ve výsledkovce | ||||
| def sloupec_s_poradim(setrizene_body): | ||||
| 	""" Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník  | ||||
| 	vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.), | ||||
| 	podle toho, jak jdou za sebou ve výsledkovce. | ||||
| 	Parametr: | ||||
| 		setrizene_body (seznam integerů): sestupně setřízená čísla | ||||
| 
 | ||||
| 	Výstup: | ||||
| 		sloupec_s_poradim (seznam stringů) | ||||
| 	""" | ||||
| 
 | ||||
| 	# ze seznamu obsahujícího setřízené body spočítáme sloupec s pořadím	 | ||||
| 	aktualni_poradi = 1 | ||||
|  | @ -358,20 +364,28 @@ def sloupec_s_poradim(setrizene_body): | |||
| 		aktualni_poradi = aktualni_poradi + velikost_skupiny | ||||
| 	return sloupec_s_poradim | ||||
| 
 | ||||
| # vrátí všechna čísla daného ročníku   | ||||
| def cisla_rocniku(rocnik, jen_verejne=True): | ||||
| 	""" Vrátí všechna čísla daného ročníku. | ||||
| 	Parametry: | ||||
| 		rocnik (Rocnik): ročník semináře | ||||
| 		jen_verejne (bool): zda se mají vrátit jen veřejná, nebo všechna čísla | ||||
| 	Vrátí: | ||||
| 		seznam objektů typu Cislo | ||||
| 	"""	 | ||||
| 	if jen_verejne: | ||||
| 		return rocnik.verejna_cisla() | ||||
| 	else: | ||||
| 		return rocnik.cisla.all() | ||||
| 
 | ||||
| # pro daný problém vrátí jeho nejvyšší nadproblém | ||||
| def hlavni_problem(problem): | ||||
| 	""" Pro daný problém vrátí jeho nejvyšší nadproblém.""" | ||||
| 	while not(problem.nadproblem == None): | ||||
| 		problem = problem.nadproblem | ||||
| 	return problem | ||||
| 
 | ||||
| def hlavni_problemy_rocniku(rocnik, jen_verejne=True): | ||||
| 	""" Pro zadaný ročník vrátí hlavní problémy ročníku, | ||||
| 	tj. ty, které už nemají nadproblém.""" | ||||
| 	hlavni_problemy = [] | ||||
| 	for cislo in cisla_rocniku(rocnik, jen_verejne): | ||||
| 		for problem in hlavni_problemy_cisla(cislo): | ||||
|  | @ -382,8 +396,8 @@ def hlavni_problemy_rocniku(rocnik, jen_verejne=True): | |||
| 	 | ||||
| 	return hlavni_problemy | ||||
| 
 | ||||
| # vrátí list všech problémů s body v daném čísle, které již nemají nadproblém | ||||
| def hlavni_problemy_cisla(cislo): | ||||
| 	""" Vrátí seznam všech problémů s body v daném čísle, které již nemají nadproblém. """ | ||||
| 	hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all()	 | ||||
| 	# hodnocení, která se vážou k danému číslu | ||||
| 	 | ||||
|  | @ -405,36 +419,71 @@ def hlavni_problemy_cisla(cislo): | |||
| 	 | ||||
| 	return hlavni_problemy | ||||
| 
 | ||||
| # vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník | ||||
| def body_resitelu_odjakziva(rocnik, resitele): | ||||
| 	# Následující řádek přidá ke každému řešiteli údaj ".body" se součtem jejich bodů | ||||
| 	resitele_s_body = Resitel.objects.annotate(body=Sum('reseni__hodnoceni__body')) | ||||
| 	# Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník indexovaný řešitelským id obsahující body | ||||
| 	# ... ale jen ro řešitele, které dostaneme jako parametr. | ||||
| 	# TODO: Zjistit, co ten parametr říká a proč je potřeba | ||||
| 	body_odjakziva = {int(res.id) : res.body for res in resitele_s_body if res in resitele} | ||||
| 	return body_odjakziva | ||||
| def body_resitelu(resitele, za, odjakziva=True): | ||||
| 	""" Funkce počítající počty bodů pro zadané řešitele,  | ||||
| 	buď odjakživa do daného ročníku/čísla anebo za daný ročník/číslo. | ||||
| 	Parametry: | ||||
| 		resitele (seznam obsahující položky typu Resitel): aktivní řešitelé | ||||
| 		za (Rocnik/Cislo): za co se mají počítat body  | ||||
| 			(generování starších výsledkovek) | ||||
| 		odjakziva (bool): zda se mají počítat body odjakživa, nebo jen za číslo/ročník | ||||
| 			zadané v "za" | ||||
| 	Výstup: | ||||
| 		slovník (Resitel.id):body | ||||
| 	"""		 | ||||
| 	resitele_id = [r.id for r in resitele] | ||||
| 	# Zjistíme, typ objektu v parametru "za" | ||||
| 	if isinstance(za, Rocnik): | ||||
| 		cislo = None | ||||
| 		rocnik = za | ||||
| 		rok = rocnik.prvni_rok | ||||
| 	elif isinstance(za, Cislo): | ||||
| 		cislo = za | ||||
| 		rocnik = None | ||||
| 		rok = cislo.rocnik.prvni_rok | ||||
| 	else: | ||||
| 		assert True, "body_resitelu: za není ani číslo ani ročník."	 | ||||
| 
 | ||||
| # vrátí slovník řešitel:body obsahující počty bodů zadaných řešitelů za daný ročník | ||||
| def body_resitelu_za_rocnik(rocnik, aktivni_resitele): | ||||
| 	body_za_rocnik = {} | ||||
| 	# inicializujeme na 0 pro všechny aktivní řešitele | ||||
| 	for ar in aktivni_resitele: | ||||
| 		body_za_rocnik[ar.id] = 0 | ||||
| 	 | ||||
| 	# spočítáme body řešitelům přes všechna řešení s hodnocením v daném ročníku | ||||
| 	print("Před dotazem:{}".format(time.time()))	 | ||||
| 	reseni = Reseni.objects.prefetch_related('resitele', 'hodnoceni_set').filter(hodnoceni__cislo_body__rocnik=rocnik) | ||||
| 	print("Po dotazu:{}".format(time.time()))	 | ||||
| 	for res in reseni: | ||||
| 		for resitel in res.resitele.all(): | ||||
| 			for hodn in res.hodnoceni_set.all(): | ||||
| 				pricti_body(body_za_rocnik, resitel, hodn.body) | ||||
| 	print("Po for-cyklu:{}".format(time.time()))	 | ||||
| 	return body_za_rocnik | ||||
| 
 | ||||
| 	# Kvůli rychlosti používáme sčítáme body už v databázi, viz  | ||||
| 	# https://docs.djangoproject.com/en/3.0/topics/db/aggregation/,  | ||||
| 	# sekce Filtering on annotations (protože potřebujeme filtrovat výsledky | ||||
| 	# jen do nějakého data, abychom uměli správně nagenerovat výsledkovky i  | ||||
| 	# za historická čísla. | ||||
| 
 | ||||
| 	# Níže se vytváří dotaz na součet bodů za správně vyfiltrovaná hodnocení,  | ||||
| 	# který se použije ve výsledném dotazu. | ||||
| 	if cislo and odjakziva: # Body se sčítají odjakživa do zadaného čísla. | ||||
| 		# Vyfiltrujeme všechna hodnocení, která jsou buď ze starších ročníků,  | ||||
| 		# anebo ze stejného ročníku, jak je zadané číslo, tam ale sčítáme jen | ||||
| 		# pro čísla s pořadím nejvýše stejným, jako má zadané číslo. | ||||
| 		body_k_zapocteni = Sum('reseni__hodnoceni__body',  | ||||
| 			filter=( Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lt=rok) | | ||||
| 				 Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok=rok, | ||||
| 				   reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi) )) | ||||
| 	elif cislo and not odjakziva: # Body se sčítají za dané číslo. | ||||
| 		body_k_zapocteni = Sum('reseni__hodnoceni__body', | ||||
| 			filter=( Q(reseni__hodnoceni__cislo_body=cislo) )) | ||||
| 	elif rocnik and odjakziva: # Spočítáme body za starší ročníky až do zadaného včetně.	 | ||||
| 		body_k_zapocteni = Sum('reseni__hodnoceni__body',  | ||||
| 			filter= Q(reseni__hodnoceni__cislo_body__rocnik__prvni_rok__lte=rok)) | ||||
| 	elif rocnik and not odjakziva: # Spočítáme body za daný ročník. | ||||
| 		body_k_zapocteni = Sum('reseni__hodnoceni__body', | ||||
| 			filter= Q(reseni__hodnoceni__cislo_body__rocnik=rocnik)) | ||||
| 	else:  | ||||
| 		assert True, "body_resitelu: Neplatná kombinace za a odjakživa." | ||||
| 
 | ||||
| 	# Následující řádek přidá ke každému řešiteli údaj ".body" se součtem jejich bodů | ||||
| 	resitele_s_body = Resitel.objects.filter(id__in=resitele_id).annotate( | ||||
| 		body=body_k_zapocteni) | ||||
| 	# Teď jen z QuerySetu řešitelů anotovaných body vygenerujeme slovník  | ||||
| 	# indexovaný řešitelským id obsahující body.  | ||||
| 	# Pokud jsou body None, nahradíme za 0. | ||||
| 	slovnik = {int(res.id) : (res.body if res.body else 0) for res in resitele_s_body} | ||||
| 	return slovnik | ||||
| 
 | ||||
| class RadekVysledkovkyRocniku(object): | ||||
| 	"""Obsahuje věci, které se hodí vědět při konstruování výsledkovky. | ||||
| 	""" Obsahuje věci, které se hodí vědět při konstruování výsledkovky. | ||||
| 	Umožňuje snazší práci v templatu (lepší, než seznam).""" | ||||
| 
 | ||||
| 	def __init__(self, poradi, resitel, body_cisla_sezn, body_rocnik, body_odjakziva, rok): | ||||
|  | @ -447,7 +496,7 @@ class RadekVysledkovkyRocniku(object): | |||
| 		self.titul = resitel.get_titul(body_odjakziva) | ||||
| 
 | ||||
| def vysledkovka_rocniku(rocnik, jen_verejne=True): | ||||
| 	"""Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve | ||||
| 	""" Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve | ||||
| 	formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" | ||||
| 	""" | ||||
| 	 | ||||
|  | @ -460,7 +509,6 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True): | |||
| 			#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik) | ||||
| 	cisla = cisla_rocniku(rocnik, jen_verejne) | ||||
| 	body_cisla_slov = {} | ||||
| 	print("Jen veřejná: {}, čísla: {}".format(jen_verejne, cisla)) | ||||
| 	for cislo in cisla: | ||||
| 		# získáme body za číslo | ||||
| 		_, cislobody = secti_body_za_cislo(cislo, aktivni_resitele) | ||||
|  | @ -476,7 +524,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True): | |||
| 	poradi = sloupec_s_poradim(setrizene_body) | ||||
| 
 | ||||
| 	# získáme body odjakživa | ||||
| 	resitel_odjakzivabody_slov = body_resitelu_odjakziva(rocnik, aktivni_resitele) | ||||
| 	resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, rocnik) | ||||
| 
 | ||||
| 	# vytvoříme jednotlivé sloupce výsledkovky | ||||
| 	radky_vysledkovky = [] | ||||
|  | @ -495,11 +543,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True): | |||
| 			setrizene_body[i], # body za ročník (spočítané výše s pořadím) | ||||
| 			resitel_odjakzivabody_slov[ar_id], # body odjakživa | ||||
| 			rocnik) # ročník semináře pro získání ročníku řešitele | ||||
| 		print("{}: číslobody - {}, ročníkbody - {}," | ||||
| 			"odjakživabody - {}".format(radek.resitel, radek.body_cisla_sezn,  | ||||
| 			radek.body_rocnik, radek.body_celkem_odjakziva)) | ||||
| 		radky_vysledkovky.append(radek) | ||||
| 		print("Přikládám {}-tý řádek.".format(i)) | ||||
| 		i += 1 | ||||
| 
 | ||||
| 	return radky_vysledkovky | ||||
|  | @ -575,8 +619,8 @@ class RadekVysledkovkyCisla(object): | |||
| 		self.titul = resitel.get_titul(body_odjakziva) | ||||
| 	 | ||||
| 
 | ||||
| # přiřazuje danému řešiteli body do slovníku | ||||
| def pricti_body(slovnik, resitel, body): | ||||
| 	""" Přiřazuje danému řešiteli body do slovníku. """ | ||||
| 	# testujeme na None (""), pokud je to první řešení  | ||||
| 	# daného řešitele, předěláme na 0 | ||||
| 	# (v dalším kroku přičteme reálný počet bodů), | ||||
|  | @ -587,15 +631,16 @@ def pricti_body(slovnik, resitel, body): | |||
| 	slovnik[resitel.id] += body | ||||
| 
 | ||||
| def secti_body_za_rocnik(rocnik, aktivni_resitele): | ||||
| 	# spočítáme všem řešitelům jejich body za ročník | ||||
| 	resitel_rocnikbody_slov = body_resitelu_za_rocnik(rocnik, aktivni_resitele) | ||||
| 	""" Spočítá body za ročník, setřídí je sestupně a vrátí jako seznam.""" | ||||
| 	# spočítáme všem řešitelům jejich body za ročník (False => ne odjakživa) | ||||
| 	resitel_rocnikbody_slov = body_resitelu(aktivni_resitele, rocnik, False) | ||||
| 	# zeptáme se na dvojice (řešitel, body) za ročník a setřídíme sestupně | ||||
| 	resitel_rocnikbody_sezn = sorted(resitel_rocnikbody_slov.items(), | ||||
| 					key = lambda x: x[1], reverse = True) | ||||
| 	return resitel_rocnikbody_sezn | ||||
| 
 | ||||
| # spočítá u řešitelů body za číslo a za jednotlivé hlavní problémy (témata) | ||||
| def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None): | ||||
| 	""" Spočítá u řešitelů body za číslo a za jednotlivé hlavní problémy (témata).""" | ||||
| 	# TODO setřídit hlavní problémy čísla podle id, ať jsou ve stejném pořadí pokaždé | ||||
| 	# pro každý hlavní problém zavedeme slovník s body za daný hlavní problém  | ||||
| 	# pro jednotlivé řešitele (slovník slovníků hlavních problémů) | ||||
|  | @ -658,8 +703,7 @@ def vysledkovka_cisla(cislo, context=None): | |||
| 	resitel_rocnikbody_sezn = secti_body_za_rocnik(cislo.rocnik, aktivni_resitele) | ||||
| 
 | ||||
| 	# získáme body odjakživa | ||||
| 	resitel_odjakzivabody_slov = body_resitelu_odjakziva(cislo.rocnik,  | ||||
| 								aktivni_resitele) | ||||
| 	resitel_odjakzivabody_slov = body_resitelu(aktivni_resitele, cislo) | ||||
| 
 | ||||
| 	# řešitelé setřídění podle bodů za číslo sestupně | ||||
| 	setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] | ||||
|  | @ -686,10 +730,7 @@ def vysledkovka_cisla(cislo, context=None): | |||
| 			setrizeni_resitele_body[i], # body za ročník (spočítané výše s pořadím) | ||||
| 			resitel_odjakzivabody_slov[ar_id], # body odjakživa | ||||
| 			cislo.rocnik) # ročník semináře pro zjištění ročníku řešitele | ||||
| 		print("{}: body za problémy - {}, číslobody - {}, ročníkbody - {}, odjakživabody - {}".format(radek.resitel,  | ||||
| 			radek.body_problemy_sezn, radek.body_cislo, radek.body_rocnik, radek.body_celkem_odjakziva)) | ||||
| 		radky_vysledkovky.append(radek) | ||||
| 		print("Přikládám {}-tý řádek.".format(i)) | ||||
| 		i += 1 | ||||
| 
 | ||||
| 	# vytahané informace předáváme do kontextu | ||||
|  | @ -698,7 +739,6 @@ def vysledkovka_cisla(cislo, context=None): | |||
| 	context['problemy'] = hlavni_problemy | ||||
| 	#context['v_cisle_zadane'] = TODO | ||||
| 	#context['resene_problemy'] = resene_problemy | ||||
| 	print("Předávám kontext.") | ||||
| 	return context | ||||
| 
 | ||||
| class CisloView(generic.DetailView): | ||||
|  | @ -736,7 +776,7 @@ class ArchivTemataView(generic.ListView): | |||
| ### Generovani vysledkovky | ||||
| 
 | ||||
| class CisloVysledkovkaView(CisloView): | ||||
| 	"View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu." | ||||
| 	"""View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu.""" | ||||
| 
 | ||||
| 	model = Cislo | ||||
| 	template_name = 'seminar/archiv/cislo_vysledkovka.tex' | ||||
|  | @ -746,7 +786,7 @@ class CisloVysledkovkaView(CisloView): | |||
| 	#vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani | ||||
| 
 | ||||
| class RocnikVysledkovkaView(RocnikView): | ||||
| 	"View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu." | ||||
| 	""" View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu.""" | ||||
| 	model = Rocnik | ||||
| 	template_name = 'seminar/archiv/rocnik_vysledkovka.tex' | ||||
| 	#content_type = 'application/x-tex; charset=UTF8' | ||||
|  | @ -832,13 +872,15 @@ def oldObalkovaniView(request, rocnik, cislo): | |||
| ### Tituly | ||||
| 
 | ||||
| def TitulyView(request, rocnik, cislo): | ||||
| 	""" View pro stažení makra titulů v TeXu.""" | ||||
| 	rocnik_obj = Rocnik.objects.get(rocnik = rocnik) | ||||
| 	resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok) | ||||
| 	cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, poradi = cislo) | ||||
| 
 | ||||
| 	asciijmena = [] | ||||
| 	jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka), pokud ano, vrátí se jako true | ||||
| 	slovnik_s_body = body_resitelu_odjakziva(rocnik_obj, resitele) | ||||
| 	jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka),  | ||||
| 		# pokud ano, vrátí se jako true | ||||
| 	slovnik_s_body = body_resitelu(resitele, rocnik_obj) | ||||
| 
 | ||||
| 	for resitel in resitele: | ||||
| 		resitel.titul = resitel.get_titul(slovnik_s_body[resitel.id]) | ||||
|  | @ -886,13 +928,13 @@ class SoustredeniUcastniciBaseView(generic.ListView): | |||
| 
 | ||||
| 
 | ||||
| class SoustredeniMailyUcastnikuView(SoustredeniUcastniciBaseView): | ||||
| 	"""Seznam e-mailů řešitelů oddělených čárkami""" | ||||
| 	""" Seznam e-mailů řešitelů oddělených čárkami. """ | ||||
| 	model = Soustredeni_Ucastnici | ||||
| 	template_name = 'seminar/soustredeni/maily_ucastniku.txt' | ||||
| 
 | ||||
| 
 | ||||
| class SoustredeniUcastniciView(SoustredeniUcastniciBaseView): | ||||
| 	"""HTML tabulka účastníků pro tisk""" | ||||
| 	""" HTML tabulka účastníků pro tisk. """ | ||||
| 	model = Soustredeni_Ucastnici | ||||
| 	template_name = 'seminar/soustredeni/seznam_ucastniku.html' | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Anet
						Anet