1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
from __future__ import absolute_import
from django.http import HttpResponse
from django.template.response import TemplateResponse
from django.views.generic import TemplateView
from .utils import (content_disposition_filename, render_pdf_from_template)
class PDFResponse(HttpResponse):
"""HttpResponse that sets the headers for PDF output."""
def __init__(self, content, status=200, content_type=None,
filename=None, show_content_in_browser=None, *args, **kwargs):
if content_type is None:
content_type = 'application/pdf'
super(PDFResponse, self).__init__(content=content,
status=status,
content_type=content_type)
self.set_filename(filename, show_content_in_browser)
def set_filename(self, filename, show_content_in_browser):
self.filename = filename
if filename:
fileheader = 'attachment; filename={0}'
if show_content_in_browser:
fileheader = 'inline; filename={0}'
filename = content_disposition_filename(filename)
header_content = fileheader.format(filename)
self['Content-Disposition'] = header_content
else:
del self['Content-Disposition']
class PDFTemplateResponse(TemplateResponse, PDFResponse):
"""Renders a Template into a PDF using wkhtmltopdf"""
def __init__(self, request, template, context=None,
status=None, content_type=None, current_app=None,
filename=None, show_content_in_browser=None,
header_template=None, footer_template=None,
cmd_options=None, *args, **kwargs):
cover_template = kwargs.pop('cover_template', None)
super(PDFTemplateResponse, self).__init__(request=request,
template=template,
context=context,
status=status,
content_type=content_type,
*args, **kwargs)
self.set_filename(filename, show_content_in_browser)
self.header_template = header_template
self.footer_template = footer_template
self.cover_template = cover_template
if cmd_options is None:
cmd_options = {}
self.cmd_options = cmd_options
@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.
"""
cmd_options = self.cmd_options.copy()
return render_pdf_from_template(
self.resolve_template(self.template_name),
self.resolve_template(self.header_template),
self.resolve_template(self.footer_template),
context=self.resolve_context(self.context_data),
request=self._request,
cmd_options=cmd_options,
cover_template=self.resolve_template(self.cover_template)
)
class PDFTemplateView(TemplateView):
"""Class-based view for HTML templates rendered to PDF."""
# Filename for downloaded PDF. If None, the response is inline.
filename = 'rendered_pdf.pdf'
# Send file as attachement. If True render content in the browser.
show_content_in_browser = False
# Filenames for the content, header, and footer templates.
template_name = None
header_template = None
footer_template = None
cover_template = None
# TemplateResponse classes for PDF and HTML
response_class = PDFTemplateResponse
html_response_class = TemplateResponse
# Command-line options to pass to wkhtmltopdf
cmd_options = {
# 'orientation': 'portrait',
# 'collate': True,
# 'quiet': None,
}
def __init__(self, *args, **kwargs):
super(PDFTemplateView, self).__init__(*args, **kwargs)
# Copy self.cmd_options to prevent clobbering the class-level object.
self.cmd_options = self.cmd_options.copy()
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
def get_cmd_options(self):
return self.cmd_options
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', None)
cmd_options = response_kwargs.pop('cmd_options', None)
if issubclass(self.response_class, PDFTemplateResponse):
if filename is None:
filename = self.get_filename()
if cmd_options is None:
cmd_options = self.get_cmd_options()
return super(PDFTemplateView, self).render_to_response(
context=context, filename=filename,
show_content_in_browser=self.show_content_in_browser,
header_template=self.header_template,
footer_template=self.footer_template,
cmd_options=cmd_options,
cover_template=self.cover_template,
**response_kwargs
)
else:
return super(PDFTemplateView, self).render_to_response(
context=context,
**response_kwargs
)
|