Created
July 17, 2014 00:01
-
-
Save ionatan-israel/d7483f9883a877da077c to your computer and use it in GitHub Desktop.
Temporal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import absolute_import | |
from tempfile import NamedTemporaryFile | |
from django.conf import settings | |
from django.http import HttpResponse | |
from django.template.response import TemplateResponse | |
from django.utils.encoding import smart_str | |
from django.views.generic import TemplateView | |
from .utils import (content_disposition_filename, make_absolute_paths, | |
wkhtmltopdf) | |
from PyPDF2 import PdfFileMerger, PdfFileReader | |
class PDFResponse(HttpResponse): | |
"""HttpResponse that sets the headers for PDF output.""" | |
def __init__(self, content, mimetype=None, 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, | |
mimetype=mimetype, | |
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, mimetype=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): | |
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, show_content_in_browser) | |
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='.html', prefix='tmp', dir=None, | |
delete=True): | |
template = self.resolve_template(template_name) | |
context = self.resolve_context(self.context_data) | |
content = smart_str(template.render(context)) | |
content = make_absolute_paths(content) | |
try: | |
# Python3 has 'buffering' arg instead of 'bufsize' | |
tempfile = NamedTemporaryFile(mode=mode, buffering=bufsize, | |
suffix=suffix, prefix=prefix, | |
dir=dir, delete=delete) | |
except TypeError: | |
tempfile = NamedTemporaryFile(mode=mode, bufsize=bufsize, | |
suffix=suffix, prefix=prefix, | |
dir=dir, delete=delete) | |
try: | |
tempfile.write(content.encode('utf-8')) | |
tempfile.flush() | |
return tempfile | |
except: | |
# Clean-up tempfile if an Exception is raised. | |
tempfile.close() | |
raise | |
def convert_to_pdf(self, filename, | |
header_filename=None, footer_filename=None): | |
cmd_options = self.cmd_options.copy() | |
# Clobber header_html and footer_html only if filenames are | |
# provided. These keys may be in self.cmd_options as hardcoded | |
# static files. | |
if header_filename is not None: | |
cmd_options['header_html'] = header_filename | |
if footer_filename is not None: | |
cmd_options['footer_html'] = footer_filename | |
return wkhtmltopdf(pages=[filename], **cmd_options) | |
def merge(self): | |
""" Fusiono los pdf temporales """ | |
merger = PdfFileMerger() | |
merger.append( | |
PdfFileReader(file( | |
settings.STATIC_ROOT.child( | |
'pdf', 'pdf_tmp.pdf').lstrip(), 'rb'))) | |
merger.append( | |
PdfFileReader(file( | |
settings.STATIC_ROOT.child( | |
'pdf', 'large_group_tmp.pdf').lstrip(), 'rb'))) | |
merger.write( | |
settings.STATIC_ROOT.child('pdf', 'outlg.pdf').lstrip()) | |
@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', settings.DEBUG) | |
input_file = header_file = footer_file = None | |
header_filename = footer_filename = 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) | |
) | |
header_filename = 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) | |
) | |
footer_filename = footer_file.name | |
data_pdf = self.convert_to_pdf( | |
filename=input_file.name, | |
header_filename=header_filename, | |
footer_filename=footer_filename) | |
tmp_pdf = settings.STATIC_ROOT.child( | |
'pdf', 'pdf_tmp.pdf') | |
result = open(tmp_pdf, 'wb') | |
result.write(data_pdf) | |
result.close() | |
self.merge() | |
with open( | |
settings.STATIC_ROOT.child('pdf', 'outlg.pdf'), 'r') as p: | |
response = HttpResponse(p.read(), mimetype='application/pdf') | |
response['Content-Disposition'] = 'inline;filename=test.pdf' | |
return response | |
p.closed | |
# return self.convert_to_pdf(filename=input_file.name, | |
# header_filename=header_filename, | |
# footer_filename=footer_filename) | |
finally: | |
# Clean up temporary files | |
for f in filter(None, (input_file, header_file, footer_file)): | |
f.close() | |
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 | |
# 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, | |
**response_kwargs | |
) | |
else: | |
return super(PDFTemplateView, self).render_to_response( | |
context=context, | |
**response_kwargs | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment