Předělání sousových views do hodně inheritance stavu

Vím, že je toho tady trochu moc najednou, ale napadalo mě to tak propleteně…
This commit is contained in:
Jonas Havelka 2024-08-02 23:36:12 +02:00
parent 4a3681b1a6
commit 05a710185c
3 changed files with 125 additions and 58 deletions

View file

@ -26,12 +26,12 @@ urlpatterns = [
),
path(
'export_ucastniku',
org_required(views.soustredeniUcastniciExportView),
org_required(views.SoustredeniUcastniciExportView.as_view()),
name='soustredeni_ucastnici_export'
),
path(
'stvrzenky.pdf',
org_required(views.soustredeniStvrzenkyView),
org_required(views.SoustredeniStvrzenkyView.as_view()),
name='soustredeni_ucastnici_stvrzenky'
),
path(

View file

@ -1,15 +1,11 @@
from django.shortcuts import get_object_or_404, render
from django.shortcuts import get_object_or_404
from django.http import HttpResponse
from django.views import generic
from django.contrib.staticfiles.finders import find
import csv
import tempfile
import shutil
import subprocess
from pathlib import Path
import http
import various.views
from seminar.views import obalkyView
from .models import Soustredeni, Soustredeni_Ucastnici
@ -34,70 +30,69 @@ class SoustredeniListView(generic.ListView):
)
class KonkretniSoustredeniMixin:
""" Přidá k View s parametrem `soustredeni` atribut `self.soustredeni` """
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
soustredeni_id = self.kwargs["soustredeni"]
self.soustredeni = get_object_or_404(Soustredeni, id=soustredeni_id)
class SoustredeniUcastniciBaseView(KonkretniSoustredeniMixin, various.views.NeprazdnyListView):
"""
Slouží jako ListView účastníků soustředění
+ háže inteligentní chybu při soustředění bez účastníků
"""
model = Soustredeni_Ucastnici
if_prazdny_title = "K soustředění nejsou přidaní žádní účastníci"
if_prazdny_text = "K tebou zvolenému soustředění nejsou přidaní žádní účastníci, tedy není co zobrazit. Můžeš to zkusit změnit v adminu, případně se zeptej webařů :-)"
def get_queryset(self):
return Soustredeni_Ucastnici.objects.filter(
soustredeni=self.soustredeni).select_related('resitel', 'resitel__osoba')
# FIXME předělat jako ostatní (vyžaduje předělání `obalkyView`)
def soustredeniObalkyView(request, soustredeni):
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
return obalkyView(request, soustredeni.ucastnici.all())
class SoustredeniUcastniciBaseView(generic.ListView):
model = Soustredeni_Ucastnici
def get_queryset(self):
soustredeni = get_object_or_404(
Soustredeni,
pk=self.kwargs["soustredeni"]
)
return Soustredeni_Ucastnici.objects.filter(
soustredeni=soustredeni).select_related('resitel')
class SoustredeniMailyUcastnikuView(SoustredeniUcastniciBaseView):
""" Seznam e-mailů řešitelů oddělených čárkami. """
model = Soustredeni_Ucastnici
template_name = 'soustredeni/maily_ucastniku.txt'
class SoustredeniUcastniciView(SoustredeniUcastniciBaseView):
""" HTML tabulka účastníků pro tisk. """
model = Soustredeni_Ucastnici
template_name = 'soustredeni/seznam_ucastniku.html'
def soustredeniUcastniciExportView(request, soustredeni):
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
ucastnici = soustredeni.ucastnici.all()
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="ucastnici.csv"'
class SoustredeniUcastniciExportView(SoustredeniUcastniciBaseView):
""" CSV tabulka účastníků. """
def render(self, request, *args, **kwargs):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="ucastnici.csv"'
writer = csv.writer(response)
writer.writerow(["jmeno", "prijmeni", "rok_maturity", "telefon", "email", "ulice", "mesto", "psc","stat"])
for u in ucastnici:
o = u.osoba
writer.writerow([o.jmeno, o.prijmeni, str(u.rok_maturity), o.telefon, o.email, o.ulice, o.mesto, o.psc, o.stat.name])
return response
writer = csv.writer(response)
writer.writerow(["jmeno", "prijmeni", "rok_maturity", "telefon", "email", "ulice", "mesto", "psc","stat"])
for u in self.object_list:
o = u.resitel.osoba
writer.writerow([o.jmeno, o.prijmeni, str(u.resitel.rok_maturity), o.telefon, o.email, o.ulice, o.mesto, o.psc, o.stat.name])
return response
def soustredeniStvrzenkyView(request, soustredeni):
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
ucastnici = soustredeni.ucastnici.all()
if ucastnici.count() == 0:
return HttpResponse(
render(request, 'universal.html', {
'title': 'Není pro koho vyrobit stvrzenky.',
'text': 'Právě ses pokusil/a vygenerovat stvrzenky pro prázdnou množinu lidí. Můžeš to zkusit změnit, případně se zeptej webařů :-)',
}),
status=http.HTTPStatus.NOT_FOUND,
)
castka = Nastaveni.get_solo().cena_sous
tex = render(request, 'soustredeni/stvrzenky.tex', {'ucastnici': ucastnici, 'soustredeni': soustredeni, 'castka': castka}).content
with tempfile.TemporaryDirectory() as tempdirfn:
tempdir = Path(tempdirfn)
with open(tempdir / "stvrzenky.tex", "w") as texfile:
texfile.write(tex.decode())
class SoustredeniStvrzenkyView(various.views.TeXResponseMixin, SoustredeniUcastniciBaseView):
template_name = 'soustredeni/stvrzenky.tex'
dalsi_potrebne_soubory = [find('images/logomm.pdf')]
shutil.copy(find('images/logomm.pdf'), tempdir)
subprocess.call(["pdflatex", "stvrzenky.tex"], cwd = tempdir, stdout=subprocess.DEVNULL)
if_prazdny_title = "Není pro koho vyrobit stvrzenky."
if_prazdny_text = "Právě ses pokusil/a vygenerovat stvrzenky pro prázdnou množinu lidí. Můžeš to zkusit změnit, případně se zeptej webařů :-)"
with open(tempdir / "stvrzenky.pdf", "rb") as pdffile:
response = HttpResponse(pdffile.read(), content_type='application/pdf')
return response
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["castka"] = Nastaveni.get_solo().cena_sous
context["soustredeni"] = self.soustredeni
context["ucastnici"] = self.object_list
return context

View file

@ -1,7 +1,14 @@
from django.http import HttpResponseForbidden
from django.shortcuts import render
import http
import tempfile
import shutil
import subprocess
# Create your views here.
from pathlib import Path
from django.http import HttpResponseForbidden, HttpResponse
from django.shortcuts import render
from django.views import generic
from django.template.loader import render_to_string
def csrf_error(request, reason=""):
@ -11,3 +18,68 @@ def csrf_error(request, reason=""):
{"url": request.META.get("HTTP_REFERER", None), "reason": reason},
status=HttpResponseForbidden.status_code,
)
class NeprazdnyListView(generic.ListView):
"""
Použití jako generic.ListView, jen při prázdném listu vyhodí M&M stránku
s titlem `self.if_prazdny_title` a textem `self.if_prazdny_text`
a způsob renderování (např. CSV) lze změnit přepsáním metody render.
"""
allow_empty = False
if_prazdny_title = "V seznamu nic není"
if_prazdny_text = "V seznamu nic není. Zkus to napravit v adminu, nebo se zeptej webařů."
# Skoro copy-paste generic.list.ListView.get,
# protože nemůžu chytat 404, neboť může nastat i v get_context_data
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
if self.get_paginate_by(self.object_list) is not None and hasattr(
self.object_list, "exists"
):
is_empty = not self.object_list.exists()
else:
is_empty = not self.object_list
if is_empty:
return render(request, 'universal.html', {
'title': self.if_prazdny_title,
'text': self.if_prazdny_text,
},
status=http.HTTPStatus.NOT_FOUND,
)
return self.render(request, *args, **kwargs)
# Tohle jsem vyčlenil, aby šlo generovat i něco jiného než template
def render(self, request, *args, **kwargs):
context = self.get_context_data()
return self.render_to_response(context)
class TeXResponseMixin:
"""
Mixin pro TemplateView, aby výsledek projel TeXem a vrátil rovnou PDF.
Obrázky a jiné soubory lze přidat nastavením `dalsi_potrebne_soubory`
(např. na `[django.contrib.staticfiles.finders.find('bla')]`,
nebo jiný seznam absolutních cest).
"""
dalsi_potrebne_soubory = []
tex = "pdflatex"
def render_to_response(self, context, **response_kwargs):
zdrojak = render_to_string(self.get_template_names(), context)
with tempfile.TemporaryDirectory() as tempdirfn:
tempdir = Path(tempdirfn)
with open(tempdir / "main.tex", "w") as texfile:
texfile.write(zdrojak)
for file in self.dalsi_potrebne_soubory:
shutil.copy(file, tempdir)
subprocess.call([self.tex, "main.tex"], cwd=tempdir, stdout=subprocess.DEVNULL)
with open(tempdir / "main.pdf", "rb") as pdffile:
response = HttpResponse(pdffile.read(), content_type='application/pdf', **response_kwargs)
return response