108 lines
3.4 KiB

"""
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):
"""
Vrátí view, který zavolá různé jiné views podle toho, kterou metodou je zavolán.
Inspirováno https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#an-alternative-better-solution, jen jsem to udělal genericky.
Parametry:
post view pro metodu POST
get view pro metodu GET
V obou případech se míní už view jakožto funkce, takže u class-based views se už má použít .as_view()
TODO: Podpora i pro metodu HEAD? A možná i pro FILES?
"""
theGetView = get
thePostView = post
class NewView(django.views.View):
def get(self, request, *args, **kwargs):
return theGetView(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
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