Rewrite PDF responses memory-based

This commit is contained in:
Claude Paroz 2019-10-04 14:38:09 +02:00
parent 067f6f96ac
commit bfb5609c9a
4 changed files with 45 additions and 45 deletions

View file

@ -1,5 +1,3 @@
import os
import tempfile
from datetime import date
from django.conf import settings
@ -50,10 +48,9 @@ class HorLine(Flowable):
class EpcBaseDocTemplate(SimpleDocTemplate):
points = '.' * 93
def __init__(self, filename, title=''):
path = os.path.join(tempfile.gettempdir(), filename)
def __init__(self, filelike, title=''):
super().__init__(
path,
filelike,
pagesize=A4,
lefMargin=2.5 * cm, bottomMargin=1 * cm, topMargin=1 * cm, rightMargin=2.5 * cm
)
@ -117,10 +114,9 @@ class ChargeSheetPDF(EpcBaseDocTemplate):
"""
Génération des feuilles de charges en pdf.
"""
def __init__(self, teacher):
def __init__(self, out, teacher):
self.teacher = teacher
filename = slugify('{0}_{1}'.format(teacher.last_name, teacher.first_name)) + '.pdf'
super().__init__(filename)
super().__init__(out)
self.addPageTemplates([
PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header)
])
@ -185,8 +181,8 @@ class UpdateDataFormPDF(EpcBaseDocTemplate):
"""
Génération des formulaires PDF de mise à jour des données.
"""
def __init__(self, filename, return_date):
super().__init__(filename)
def __init__(self, out, return_date):
super().__init__(out)
self.text = (
"Afin de mettre à jour nos bases de données, nous vous serions reconnaissant "
"de contrôler les données ci-dessous qui vous concernent selon votre filière "
@ -415,12 +411,9 @@ class CompensationForm:
class ExpertEdeLetterPdf(CompensationForm, EpcBaseDocTemplate):
def __init__(self, student):
def __init__(self, out, student):
self.student = student
filename = slugify(
'{0}_{1}'.format(self.student.last_name, self.student.first_name)
) + '_Expert.pdf'
super().__init__(filename)
super().__init__(out)
self.addPageTemplates([
PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header),
PageTemplate(id='ISOPage', frames=[self.page_frame], onPage=self.header_iso),
@ -501,12 +494,9 @@ class ExpertEdeLetterPdf(CompensationForm, EpcBaseDocTemplate):
class MentorCompensationPdfForm(CompensationForm, EpcBaseDocTemplate):
def __init__(self, student):
def __init__(self, out, student):
self.student = student
filename = slugify(
'{0}_{1}'.format(self.student.last_name, self.student.first_name)
) + '_Indemn_mentor.pdf'
super().__init__(filename)
super().__init__(out)
self.addPageTemplates([
PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header_iso)
])
@ -533,10 +523,9 @@ class KlassListPDF(EpcBaseDocTemplate):
"""
Génération des rôles de classes en pdf.
"""
def __init__(self, klass):
def __init__(self, out, klass):
self.klass = klass
filename = slugify('{0}'.format(klass.name)) + '.pdf'
super().__init__(filename)
super().__init__(out)
self.addPageTemplates([
PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header),

View file

@ -345,7 +345,7 @@ tél. 032 886 33 00
'attachment; filename="dupond_albin_Expert.pdf"'
)
self.assertEqual(response['Content-Type'], 'application/pdf')
self.assertGreater(len(response.content), 200)
self.assertGreater(int(response['Content-Length']), 1000)
# Expert without corporation
st.expert = CorpContact.objects.create(first_name='James', last_name='Bond')
st.save()
@ -361,7 +361,7 @@ tél. 032 886 33 00
'attachment; filename="dupond_albin_Indemn_mentor.pdf"'
)
self.assertEqual(response['Content-Type'], 'application/pdf')
self.assertGreater(len(response.content), 200)
self.assertGreater(int(response['Content-Length']), 1000)
def test_EDEpe_klass(self):
lev3 = Level.objects.create(name='3')

View file

@ -1,3 +1,4 @@
import io
import json
import os
@ -8,7 +9,7 @@ from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.mail import EmailMessage
from django.db.models import Count
from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect
from django.http import FileResponse, HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.template import loader
from django.urls import reverse, reverse_lazy
@ -536,9 +537,10 @@ class PrintUpdateForm(ZippedFilesBaseView):
def generate_files(self):
for klass in Klass.objects.filter(level__gte=2
).exclude(section__name='MP_ASSC').exclude(section__name='MP_ASE'):
pdf = UpdateDataFormPDF('{0}.pdf'.format(klass.name), self.return_date)
buff = io.BytesIO()
pdf = UpdateDataFormPDF(buff, self.return_date)
pdf.produce(klass)
yield pdf.filename
yield ('{0}.pdf'.format(klass.name), buff.getvalue())
def print_expert_ede_compensation_form(request, pk):
@ -554,13 +556,14 @@ def print_expert_ede_compensation_form(request, pk):
+ missing
))
return redirect(reverse("admin:stages_student_change", args=(student.pk,)))
pdf = ExpertEdeLetterPdf(student)
buff = io.BytesIO()
pdf = ExpertEdeLetterPdf(buff, student)
pdf.produce()
with open(pdf.filename, mode='rb') as fh:
response = HttpResponse(fh.read(), content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="{0}"'.format(os.path.basename(pdf.filename))
return response
filename = slugify(
'{0}_{1}'.format(student.last_name, student.first_name)
) + '_Expert.pdf'
buff.seek(0)
return FileResponse(buff, as_attachment=True, filename=filename)
def print_mentor_ede_compensation_form(request, pk):
@ -571,13 +574,16 @@ def print_mentor_ede_compensation_form(request, pk):
if not student.mentor:
messages.error(request, "Aucun mentor n'est attribué à cet étudiant")
return redirect(reverse("admin:stages_student_change", args=(student.pk,)))
pdf = MentorCompensationPdfForm(student)
buff = io.BytesIO()
pdf = MentorCompensationPdfForm(buff, student)
pdf.produce()
filename = slugify(
'{0}_{1}'.format(student.last_name, student.first_name)
) + '_Indemn_mentor.pdf'
buff.seek(0)
return FileResponse(buff, as_attachment=True, filename=filename)
with open(pdf.filename, mode='rb') as fh:
response = HttpResponse(fh.read(), content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="{0}"'.format(os.path.basename(pdf.filename))
return response
class PrintKlassList(ZippedFilesBaseView):
@ -585,9 +591,11 @@ class PrintKlassList(ZippedFilesBaseView):
def generate_files(self):
for klass in Klass.active.order_by('section', 'name'):
pdf = KlassListPDF(klass)
buff = io.BytesIO()
pdf = KlassListPDF(buff, klass)
pdf.produce(klass)
yield pdf.filename
filename = slugify('{0}.pdf'.format(klass.name))
yield (filename, buff.getvalue())
class PrintChargeSheet(ZippedFilesBaseView):
@ -601,6 +609,8 @@ class PrintChargeSheet(ZippedFilesBaseView):
queryset = Teacher.objects.filter(pk__in=self.request.GET.get('ids').split(','))
for teacher in queryset:
activities = teacher.calc_activity()
pdf = ChargeSheetPDF(teacher)
buff = io.BytesIO()
pdf = ChargeSheetPDF(buff, teacher)
pdf.produce(activities)
yield pdf.filename
filename = slugify('{0}_{1}.pdf'.format(teacher.last_name, teacher.first_name))
yield (filename, buff.getvalue())

View file

@ -56,13 +56,14 @@ class ZippedFilesBaseView(View):
filename = 'to_be_defined.zip'
def generate_files(self):
"""Generator yielding (file_name, file_data) tuples."""
raise NotImplementedError()
def get(self, request, *args, **kwargs):
tmp_file = tempfile.NamedTemporaryFile()
with zipfile.ZipFile(tmp_file, mode='w', compression=zipfile.ZIP_DEFLATED) as filezip:
for file_name in self.generate_files():
filezip.write(file_name, arcname=os.path.basename(file_name))
for file_name, file_data in self.generate_files():
filezip.writestr(file_name, file_data)
with open(filezip.filename, mode='rb') as fh:
response = HttpResponse(fh.read(), content_type='application/zip')