From 5a1eedb7b192ab15371e2bfcd9fcb430815170b9 Mon Sep 17 00:00:00 2001 From: ticvac Date: Wed, 29 Jan 2025 18:17:00 +0100 Subject: [PATCH 1/5] ruzne exporty resitelu --- .../personalni/profil/export_lidi.html | 88 +++++++++++++ .../personalni/profil/orgorozcestnik.html | 7 ++ personalni/urls.py | 22 ++++ personalni/views.py | 118 +++++++++++++++++- tvorba/utils.py | 22 ++++ 5 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 personalni/templates/personalni/profil/export_lidi.html diff --git a/personalni/templates/personalni/profil/export_lidi.html b/personalni/templates/personalni/profil/export_lidi.html new file mode 100644 index 00000000..96778449 --- /dev/null +++ b/personalni/templates/personalni/profil/export_lidi.html @@ -0,0 +1,88 @@ +{% extends "base.html" %} + + +{% block content %} + +

Export lidí

+ + + + + + + + + +{% endblock %} diff --git a/personalni/templates/personalni/profil/orgorozcestnik.html b/personalni/templates/personalni/profil/orgorozcestnik.html index 2dbc853b..bd73fa6e 100644 --- a/personalni/templates/personalni/profil/orgorozcestnik.html +++ b/personalni/templates/personalni/profil/orgorozcestnik.html @@ -107,6 +107,13 @@ +
+

Exporty dat lidí v semináří

+ + +

Nemůžeš najít, co hledáš? Může to být v administračním rozhraní webu.

{% endblock content %} diff --git a/personalni/urls.py b/personalni/urls.py index 1805bbfe..9e173aae 100644 --- a/personalni/urls.py +++ b/personalni/urls.py @@ -38,6 +38,28 @@ urlpatterns = [ 'org/propagace/jak-se-dozvedeli/', org_required(views.JakSeDozvedeliView.as_view()), name='jak_se_dozvedeli' + ), + + # export dat o řešitelích + path( + 'profil/exporty_lidi', + org_required(views.ExportLidiView.as_view()), + name='exporty_lidi', + ), + path( + 'profil/exporty_lidi/get/', + org_required(views.get_export_options), + name='exporty_lidi_options', + ), + path( + 'profil/exporty_lidi/get_csv_only_one_step/', + org_required(views.download_export_csv_only_first_step), + name='exporty_lidi_data', + ), + path( + 'profil/exporty_lidi/get_csv//', + org_required(views.download_export_csv), + name='exporty_lidi_download', ) ] diff --git a/personalni/views.py b/personalni/views.py index 49442c2d..5ae97e24 100644 --- a/personalni/views.py +++ b/personalni/views.py @@ -20,13 +20,16 @@ from django.utils import timezone import personalni.models as m from soustredeni.models import Soustredeni from odevzdavatko.models import Hodnoceni -from tvorba.models import Clanek, Uloha, Tema +from tvorba.models import Clanek, Uloha, Tema, Cislo, Rocnik +import tvorba.utils as tvorba_utils from various.models import Nastaveni from .forms import PrihlaskaForm, ProfileEditForm, PoMaturiteProfileEditForm from datetime import date import logging import csv +from enum import Enum +import json from various.views.pomocne import formularOKView from various.autentizace.views import LoginView @@ -140,7 +143,54 @@ class OrgoRozcestnikView(TemplateView): #content_type = 'text/plain; charset=UTF8' #XXX + +class PrvniTypExportu(Enum): + CISLA = 1 + ROCNIKU = 2 + SOUSTREDENI = 4 +class ExportLidiView(TemplateView): + template_name = 'personalni/profil/export_lidi.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['typy_exportu'] = json.dumps({member.value: member.name.lower().capitalize() for member in PrvniTypExportu}) + return context + + +def get_export_options(request, type): + if type == PrvniTypExportu.CISLA.value: + data = [{"id": c.id, "display": str(c)} for c in Cislo.objects.all()] + if type == PrvniTypExportu.ROCNIKU.value: + data = [{"id": r.id, "display": str(r)} for r in Rocnik.objects.all()] + if type == PrvniTypExportu.SOUSTREDENI.value: + data = [{"id": s.id, "display": str(s)} for s in Soustredeni.objects.all()] + return HttpResponse(json.dumps(data), content_type='application/json') + +def download_export_csv_only_first_step(request, type): + if type == 3: + response = dataResiteluCsvResponse(tvorba_utils.resitele_co_neodmaturovali()) + response['Content-Disposition'] = 'attachment; filename="resitele_co_neodmaturovali.csv"' + return response + +def download_export_csv(request, type, id): + if type == PrvniTypExportu.CISLA.value: + response = dataResiteluCsvResponse(tvorba_utils.resi_cislo(Cislo.objects.get(id=id))) + name = str(Cislo.objects.get(id=id)).replace(" ", "_") + "_resitele_cisla.csv" + response['Content-Disposition'] = 'attachment; filename="' + name + '"' + return response + if type == PrvniTypExportu.ROCNIKU.value: + response = dataResiteluCsvResponse(tvorba_utils.resi_v_rocniku(Rocnik.objects.get(id=id))) + name = str(Rocnik.objects.get(id=id)).replace(" ", "_") + "_resitele_rocniku.csv" + response['Content-Disposition'] = 'attachment; filename="' + name + '"' + return response + if type == PrvniTypExportu.SOUSTREDENI.value: + soustredeni = Soustredeni.objects.get(id=id) + organizatori = soustredeni.organizatori.all() + response = dataOsobCsvResponse(organizatori) + name = str(soustredeni).replace(" ", "_") + "_organizatori_soustredeni.csv" + response['Content-Disposition'] = 'attachment; filename="' + name + '"' + return response class ResitelView(LoginRequiredMixin,generic.DetailView): model = m.Resitel @@ -470,3 +520,69 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True): writer.writerows(queryset_list) return response + +def dataOsobCsvResponse(queryset, columns=None, with_header=True): + """Pomocná funkce pro vracení dat osob jako CSV. Musí dostat správný QuerySet, který dává Ososby""" + + default_columns = ( + 'id', + 'osoba__jmeno', + 'osoba__prijmeni', + 'osoba__prezdivka', + 'osoba__email', + 'osoba__telefon', + 'osoba__user__username', + 'osoba__datum_narozeni', + 'osoba__osloveni', + 'osoba__ulice', + 'osoba__mesto', + 'osoba__psc', + 'osoba__stat', + 'osoba__jak_se_dozvedeli', + 'osoba__poznamka', + 'osoba__datum_registrace', + 'osoba__datum_souhlasu_udaje', + 'osoba__datum_souhlasu_zasilani', + ) + if columns is None: columns = default_columns + + field_name_overrides = { + # Zrušení prefixu "osoba__" + 'osoba__jmeno': 'jmeno', + 'osoba__prijmeni': 'prijmeni', + 'osoba__prezdivka': 'prezdivka', + 'osoba__email': 'email', + 'osoba__telefon': 'telefon', + 'osoba__user__username': 'user', + 'osoba__datum_narozeni': 'datum_narozeni', + 'osoba__osloveni': 'osloveni', + 'osoba__ulice': 'ulice', + 'osoba__mesto': 'mesto', + 'osoba__psc': 'psc', + 'osoba__stat': 'stat', + 'osoba__jak_se_dozvedeli': 'jak_se_dozvedeli', + 'osoba__poznamka': 'poznamka', + 'osoba__datum_registrace': 'datum_registrace', + 'osoba__datum_souhlasu_udaje': 'datum_souhlasu_udaje', + 'osoba__datum_souhlasu_zasilani':'datum_souhlasu_zasilani', + } + + def get_field_name(column_name): + if column_name in field_name_overrides: + return field_name_overrides[column_name] + return column_name + + response = HttpResponse(content_type='text/csv') + writer = csv.writer(response) + + # První řádek je záhlaví + if with_header: + writer.writerow(map(get_field_name, columns)) + + # Data: + queryset_list = queryset.values_list(*columns) + writer.writerows(queryset_list) + + return response + + diff --git a/tvorba/utils.py b/tvorba/utils.py index c2feadd9..1c8076c8 100644 --- a/tvorba/utils.py +++ b/tvorba/utils.py @@ -27,6 +27,28 @@ def resi_v_rocniku(rocnik, cislo=None): reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik, reseni__hodnoceni__deadline_body__cislo__poradi__lte=cislo.poradi ).distinct() + +def resi_cislo(cislo): + """ Vrátí seznam řešitelů, co vyřešili nějaký problém v daném čísle. + Parametry: + cislo (typu Cislo) číslo, ve kterém chci řešitele, co něco odevzdali + Výstup: + QuerySet objektů typu Resitel + + Nejsem si moc jistý, jestli to tak funguje... Vašek """ + + return personalni.models.Resitel.objects.filter( + reseni__hodnoceni__deadline_body__cislo=cislo + ).distinct() + +def resitele_co_neodmaturovali(): + """ Vrátí seznam řešitelů, co ještě neodmaturovali. + Výstup: + QuerySet objektů typu Resitel """ + from datetime import datetime + current_year = datetime.now().year + '''Člověk odmaturuje když je jeho rok maturity menší nebo stejný jako aktuální rok? ''' + return personalni.models.Resitel.objects.filter(rok_maturity__gte=current_year) def aktivniResitele(cislo, pouze_letosni=False): -- 2.39.5 From 3814d292adc1c4fbdc1be2a1e0eab61ce0d8aa24 Mon Sep 17 00:00:00 2001 From: ticvac Date: Wed, 26 Feb 2025 19:11:50 +0100 Subject: [PATCH 2/5] oprava na query set osob --- personalni/views.py | 60 ++++++++++++++------------------------------- tvorba/utils.py | 2 ++ 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/personalni/views.py b/personalni/views.py index 5ae97e24..49938f29 100644 --- a/personalni/views.py +++ b/personalni/views.py @@ -187,7 +187,8 @@ def download_export_csv(request, type, id): if type == PrvniTypExportu.SOUSTREDENI.value: soustredeni = Soustredeni.objects.get(id=id) organizatori = soustredeni.organizatori.all() - response = dataOsobCsvResponse(organizatori) + organizatoriOsoby = Osoba.objects.filter(org__in=organizatori) + response = dataOsobCsvResponse(organizatoriOsoby, columns=("jmeno", "prijmeni", "email", "telefon",)) name = str(soustredeni).replace(" ", "_") + "_organizatori_soustredeni.csv" response['Content-Disposition'] = 'attachment; filename="' + name + '"' return response @@ -526,50 +527,27 @@ def dataOsobCsvResponse(queryset, columns=None, with_header=True): default_columns = ( 'id', - 'osoba__jmeno', - 'osoba__prijmeni', - 'osoba__prezdivka', - 'osoba__email', - 'osoba__telefon', - 'osoba__user__username', - 'osoba__datum_narozeni', - 'osoba__osloveni', - 'osoba__ulice', - 'osoba__mesto', - 'osoba__psc', - 'osoba__stat', - 'osoba__jak_se_dozvedeli', - 'osoba__poznamka', - 'osoba__datum_registrace', - 'osoba__datum_souhlasu_udaje', - 'osoba__datum_souhlasu_zasilani', + 'jmeno', + 'prijmeni', + 'prezdivka', + 'email', + 'telefon', + 'datum_narozeni', + 'osloveni', + 'ulice', + 'mesto', + 'psc', + 'stat', + 'jak_se_dozvedeli', + 'poznamka', + 'datum_registrace', + 'datum_souhlasu_udaje', + 'datum_souhlasu_zasilani', ) + if columns is None: columns = default_columns - field_name_overrides = { - # Zrušení prefixu "osoba__" - 'osoba__jmeno': 'jmeno', - 'osoba__prijmeni': 'prijmeni', - 'osoba__prezdivka': 'prezdivka', - 'osoba__email': 'email', - 'osoba__telefon': 'telefon', - 'osoba__user__username': 'user', - 'osoba__datum_narozeni': 'datum_narozeni', - 'osoba__osloveni': 'osloveni', - 'osoba__ulice': 'ulice', - 'osoba__mesto': 'mesto', - 'osoba__psc': 'psc', - 'osoba__stat': 'stat', - 'osoba__jak_se_dozvedeli': 'jak_se_dozvedeli', - 'osoba__poznamka': 'poznamka', - 'osoba__datum_registrace': 'datum_registrace', - 'osoba__datum_souhlasu_udaje': 'datum_souhlasu_udaje', - 'osoba__datum_souhlasu_zasilani':'datum_souhlasu_zasilani', - } - def get_field_name(column_name): - if column_name in field_name_overrides: - return field_name_overrides[column_name] return column_name response = HttpResponse(content_type='text/csv') diff --git a/tvorba/utils.py b/tvorba/utils.py index 1c8076c8..a7b016a9 100644 --- a/tvorba/utils.py +++ b/tvorba/utils.py @@ -48,6 +48,8 @@ def resitele_co_neodmaturovali(): from datetime import datetime current_year = datetime.now().year '''Člověk odmaturuje když je jeho rok maturity menší nebo stejný jako aktuální rok? ''' + if datetime.now().month < 8: + current_year -= 1 return personalni.models.Resitel.objects.filter(rok_maturity__gte=current_year) -- 2.39.5 From be4fda5e7fde77cde2a489a1e7d8a424d2125532 Mon Sep 17 00:00:00 2001 From: ticvac Date: Wed, 26 Feb 2025 19:17:06 +0100 Subject: [PATCH 3/5] oprava url na spravny tvar --- personalni/templates/personalni/profil/orgorozcestnik.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/personalni/templates/personalni/profil/orgorozcestnik.html b/personalni/templates/personalni/profil/orgorozcestnik.html index bd73fa6e..338857ba 100644 --- a/personalni/templates/personalni/profil/orgorozcestnik.html +++ b/personalni/templates/personalni/profil/orgorozcestnik.html @@ -111,7 +111,7 @@

Exporty dat lidí v semináří


-- 2.39.5 From b7ac8417603f924f1f6968a99024edae16e90ba3 Mon Sep 17 00:00:00 2001 From: ticvac Date: Wed, 26 Feb 2025 19:21:01 +0100 Subject: [PATCH 4/5] komentar maturity --- tvorba/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tvorba/utils.py b/tvorba/utils.py index a7b016a9..41ac578a 100644 --- a/tvorba/utils.py +++ b/tvorba/utils.py @@ -34,8 +34,7 @@ def resi_cislo(cislo): cislo (typu Cislo) číslo, ve kterém chci řešitele, co něco odevzdali Výstup: QuerySet objektů typu Resitel - - Nejsem si moc jistý, jestli to tak funguje... Vašek """ + """ return personalni.models.Resitel.objects.filter( reseni__hodnoceni__deadline_body__cislo=cislo @@ -43,11 +42,12 @@ def resi_cislo(cislo): def resitele_co_neodmaturovali(): """ Vrátí seznam řešitelů, co ještě neodmaturovali. + Pokud ještě není srpen, tak tak zahrnuje i ty, kteří odmaturovali letos. + Výstup: QuerySet objektů typu Resitel """ from datetime import datetime current_year = datetime.now().year - '''Člověk odmaturuje když je jeho rok maturity menší nebo stejný jako aktuální rok? ''' if datetime.now().month < 8: current_year -= 1 return personalni.models.Resitel.objects.filter(rok_maturity__gte=current_year) -- 2.39.5 From d86bdf9218166101ba96352c4f55889ab9e779f1 Mon Sep 17 00:00:00 2001 From: ticvac Date: Wed, 26 Feb 2025 19:35:00 +0100 Subject: [PATCH 5/5] tak odebrano --- tvorba/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tvorba/utils.py b/tvorba/utils.py index 41ac578a..312e83e6 100644 --- a/tvorba/utils.py +++ b/tvorba/utils.py @@ -42,7 +42,7 @@ def resi_cislo(cislo): def resitele_co_neodmaturovali(): """ Vrátí seznam řešitelů, co ještě neodmaturovali. - Pokud ještě není srpen, tak tak zahrnuje i ty, kteří odmaturovali letos. + Pokud ještě není srpen, tak zahrnuje i ty, kteří odmaturovali letos. Výstup: QuerySet objektů typu Resitel """ -- 2.39.5