Merge pull request 'Předělání sousových views' (!57) from predelani_sousovych_view into master
Reviewed-on: #57
This commit is contained in:
commit
5883a5cd28
4 changed files with 134 additions and 54 deletions
|
@ -29,7 +29,7 @@
|
|||
}
|
||||
|
||||
{% for u in ucastnici %}
|
||||
{% with o=u.osoba %}
|
||||
{% with o=u.resitel.osoba %}
|
||||
\stvrzenka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
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 personalni.views
|
||||
import various.views.generic
|
||||
from personalni.views import obalkyView
|
||||
|
||||
from .models import Soustredeni, Soustredeni_Ucastnici
|
||||
from various.models import Nastaveni
|
||||
|
@ -34,73 +30,78 @@ class SoustredeniListView(generic.ListView):
|
|||
)
|
||||
|
||||
|
||||
def soustredeniObalkyView(request, soustredeni):
|
||||
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
|
||||
return personalni.views.obalkyView(request, soustredeni.ucastnici.all())
|
||||
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(generic.ListView):
|
||||
class SoustredeniUcastniciBaseView(
|
||||
KonkretniSoustredeniMixin,
|
||||
various.views.generic.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):
|
||||
soustredeni = get_object_or_404(
|
||||
Soustredeni,
|
||||
pk=self.kwargs["soustredeni"]
|
||||
)
|
||||
return Soustredeni_Ucastnici.objects.filter(
|
||||
soustredeni=soustredeni).select_related('resitel')
|
||||
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 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.generic.TeXResponseMixin,
|
||||
SoustredeniUcastniciBaseView,
|
||||
):
|
||||
template_name = 'soustredeni/stvrzenky.tex'
|
||||
dalsi_potrebne_soubory = [find('soustredeni/logomm.pdf')]
|
||||
|
||||
shutil.copy(find('soustredeni/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
|
||||
|
||||
class SoustredeniAbstraktyView(generic.DetailView):
|
||||
model = Soustredeni
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
"""
|
||||
Stejně jako je `django.views.generic` jsou zde generické Views
|
||||
a pár mixinů, které upravují chování Views.
|
||||
"""
|
||||
|
||||
import http
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import django.views
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.template.loader import render_to_string
|
||||
from django.views import generic
|
||||
|
||||
|
||||
def viewMethodSwitch(get, post):
|
||||
"""
|
||||
|
@ -27,3 +44,65 @@ def viewMethodSwitch(get, post):
|
|||
return thePostView(request, *args, **kwargs)
|
||||
|
||||
return NewView.as_view()
|
||||
|
||||
|
||||
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 # Interní djangová věc
|
||||
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_prikaz = "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_prikaz, "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
|
||||
|
||||
|
|
Loading…
Reference in a new issue