aboutsummaryrefslogtreecommitdiffstats
path: root/wkhtmltopdf/views.py
diff options
context:
space:
mode:
authorSimon Law <simon.law@ecometrica.com>2012-07-24 14:57:06 -0400
committerSimon Law <simon.law@ecometrica.com>2012-07-24 14:57:06 -0400
commit8e53c5bc5db462f6e39404c73ac96ec0cbb6a6c7 (patch)
treee88c55a0ba32e5222547a2edb02a589a6cad6e84 /wkhtmltopdf/views.py
parent4a27fe9f16ecd4bc6f94ad89046767450316490c (diff)
downloaddjango-wkhtmltopdf-8e53c5bc5db462f6e39404c73ac96ec0cbb6a6c7.tar.gz
django-wkhtmltopdf-8e53c5bc5db462f6e39404c73ac96ec0cbb6a6c7.tar.bz2
django-wkhtmltopdf-8e53c5bc5db462f6e39404c73ac96ec0cbb6a6c7.zip
PDFTemplateResponse and PDFTemplateView now match Django's implementations
PDFTemplateResponse is like TemplateResponse in that it does dynamic rendering of a template on the fly. PDFTemplateView has a much smaller implementation, relying on PDFTemplateResponse to do the rendering for it. It also knows about the standard TemplateResponse when it needs to render the HTML version.
Diffstat (limited to 'wkhtmltopdf/views.py')
-rw-r--r--wkhtmltopdf/views.py174
1 files changed, 139 insertions, 35 deletions
diff --git a/wkhtmltopdf/views.py b/wkhtmltopdf/views.py
index 539a669..0e91b2a 100644
--- a/wkhtmltopdf/views.py
+++ b/wkhtmltopdf/views.py
@@ -2,28 +2,40 @@ from __future__ import absolute_import
import os
from re import compile
+from tempfile import NamedTemporaryFile
import warnings
from django.conf import settings
from django.contrib.sites.models import Site
+from django.http import HttpResponse
from django.template.context import RequestContext
-from django.template.response import HttpResponse
+from django.template.response import TemplateResponse
from django.views.generic import TemplateView
-from .utils import (content_disposition_filename,
- template_to_temp_file, wkhtmltopdf)
+from .utils import (content_disposition_filename, wkhtmltopdf)
class PDFResponse(HttpResponse):
def __init__(self, content, mimetype=None, status=200,
- content_type='application/pdf', *args, **kwargs):
- filename = kwargs.pop('filename', None)
- super(PDFResponse, self).__init__(content, mimetype, status,
- content_type, *args, **kwargs)
+ content_type=None, filename=None, *args, **kwargs):
+
+ if content_type is None:
+ content_type = 'application/pdf'
+
+ super(PDFResponse, self).__init__(content=content,
+ mimetype=mimetype,
+ status=status,
+ content_type=content_type)
+ self.set_filename(filename)
+
+ def set_filename(self, filename):
+ self.filename = filename
if filename:
filename = content_disposition_filename(filename)
header_content = 'attachment; filename={0}'.format(filename)
self['Content-Disposition'] = header_content
+ else:
+ del self['Content-Disposition']
class PdfResponse(PDFResponse):
@@ -33,6 +45,94 @@ class PdfResponse(PDFResponse):
super(PdfResponse, self).__init__(content, filename=filename)
+class PDFTemplateResponse(TemplateResponse, PDFResponse):
+ """Renders a Template into a PDF using wkhtmltopdf"""
+
+ def __init__(self, request, template, context=None, mimetype=None,
+ status=None, content_type=None, current_app=None,
+ filename=None, header_template=None, footer_template=None,
+ cmd_options=None, *args, **kwargs):
+
+ super(PDFTemplateResponse, self).__init__(request=request,
+ template=template,
+ context=context,
+ mimetype=mimetype,
+ status=status,
+ content_type=content_type,
+ current_app=None,
+ *args, **kwargs)
+ self.set_filename(filename)
+
+ self.header_template = header_template
+ self.footer_template = footer_template
+
+ if cmd_options is None:
+ cmd_options = {}
+ self.cmd_options = cmd_options
+
+ def render_to_temporary_file(self, template_name, mode='w+b', bufsize=-1,
+ suffix='', prefix='tmp', dir=None,
+ delete=True):
+ template = self.resolve_template(template_name)
+ context = self.resolve_context(self.context_data)
+ content = template.render(context)
+ tempfile = NamedTemporaryFile(mode=mode, bufsize=bufsize,
+ suffix=suffix, prefix=prefix,
+ dir=dir, delete=delete)
+ try:
+ tempfile.write(content)
+ tempfile.flush()
+ return tempfile
+ except:
+ # Clean-up tempfile if an Exception is raised.
+ tempfile.close()
+ raise
+
+ @property
+ def rendered_content(self):
+ """Returns the freshly rendered content for the template and context
+ described by the PDFResponse.
+
+ This *does not* set the final content of the response. To set the
+ response content, you must either call render(), or set the
+ content explicitly using the value of this property.
+ """
+ debug = getattr(settings, 'WKHTMLTOPDF_DEBUG', False)
+
+ cmd_options = self.cmd_options.copy()
+
+ input_file = header_file = footer_file = None
+
+ try:
+ input_file = self.render_to_temporary_file(
+ template_name=self.template_name,
+ prefix='wkhtmltopdf', suffix='.html',
+ delete=(not debug)
+ )
+
+ if self.header_template:
+ header_file = self.render_to_temporary_file(
+ template_name=self.header_template,
+ prefix='wkhtmltopdf', suffix='.html',
+ delete=(not debug)
+ )
+ cmd_options.setdefault('header_html', header_file.name)
+
+ if self.footer_template:
+ footer_file = self.render_to_temporary_file(
+ template_name=self.footer_template,
+ prefix='wkhtmltopdf', suffix='.html',
+ delete=(not debug)
+ )
+ cmd_options.setdefault('footer_html', footer_file.name)
+
+ return wkhtmltopdf(pages=[input_file.name], **cmd_options)
+ finally:
+ # Clean up temporary files
+ for f in filter(None, (input_file, header_file, footer_file)):
+ f.close()
+
+
class PDFTemplateView(TemplateView):
filename = 'rendered_pdf.pdf'
footer_template = None
@@ -42,28 +142,20 @@ class PDFTemplateView(TemplateView):
margin_left = 0
margin_right = 0
margin_top = 0
- response = PDFResponse
- _tmp_files = None
-
- def __init__(self, *args, **kwargs):
- self._tmp_files = []
- super(PDFTemplateView, self).__init__(*args, **kwargs)
-
- def get(self, request, context_instance=None, *args, **kwargs):
- if request.GET.get('as', '') == 'html':
- return super(PDFTemplateView, self).get(request, *args, **kwargs)
-
- if context_instance:
- self.context_instance = context_instance
- else:
- self.context_instance = RequestContext(request, self.get_context_data(**kwargs))
-
- page_path = template_to_temp_file(self.get_template_names(), self.get_context_data(), self.context_instance)
- pdf_kwargs = self.get_pdf_kwargs()
- output = wkhtmltopdf(page_path, **pdf_kwargs)
- if self._tmp_files:
- map(os.remove, self._tmp_files)
- return self.response(output, filename=self.get_filename())
+ response_class = PDFTemplateResponse
+ html_response_class = TemplateResponse
+
+ def get(self, request, *args, **kwargs):
+ response_class = self.response_class
+ try:
+ if request.GET.get('as', '') == 'html':
+ # Use the html_response_class if HTML was requested.
+ self.response_class = self.html_response_class
+ return super(PDFTemplateView, self).get(request,
+ *args, **kwargs)
+ finally:
+ # Remove self.response_class
+ self.response_class = response_class
def get_filename(self):
return self.filename
@@ -76,12 +168,6 @@ class PDFTemplateView(TemplateView):
'margin_top': self.margin_top,
'orientation': self.orientation,
}
- if self.header_template:
- kwargs['header_html'] = template_to_temp_file(self.header_template, self.get_context_data(), self.context_instance)
- self._tmp_files.append(kwargs['header_html'])
- if self.footer_template:
- kwargs['footer_html'] = template_to_temp_file(self.footer_template, self.get_context_data(), self.context_instance)
- self._tmp_files.append(kwargs['footer_html'])
return kwargs
def get_context_data(self, **kwargs):
@@ -95,6 +181,24 @@ class PDFTemplateView(TemplateView):
return context
+ def render_to_response(self, context, **response_kwargs):
+ """
+ Returns a PDF response with a template rendered with the given context.
+ """
+ filename = response_kwargs.pop('filename', self.get_filename())
+ cmd_options = response_kwargs.pop('cmd_options', self.get_pdf_kwargs())
+
+ if issubclass(self.response_class, PDFTemplateResponse):
+ return super(PDFTemplateView, self).render_to_response(
+ context=context, filename=filename, cmd_options=cmd_options,
+ **response_kwargs
+ )
+ else:
+ return super(PDFTemplateView, self).render_to_response(
+ context=context,
+ **response_kwargs
+ )
+
class PdfTemplateView(PDFTemplateView): #TODO: Remove this in v1.0
def __init__(self, *args, **kwargs):