aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--wkhtmltopdf/tests.py52
-rw-r--r--wkhtmltopdf/utils.py6
-rw-r--r--wkhtmltopdf/views.py63
3 files changed, 98 insertions, 23 deletions
diff --git a/wkhtmltopdf/tests.py b/wkhtmltopdf/tests.py
index 1802440..764c7f2 100644
--- a/wkhtmltopdf/tests.py
+++ b/wkhtmltopdf/tests.py
@@ -117,7 +117,13 @@ class TestViews(TestCase):
with override_settings(
MEDIA_URL='/media/',
+ MEDIA_ROOT='/tmp/media',
STATIC_URL='/static/',
+ STATIC_ROOT='/tmp/static',
+ TEMPLATE_CONTEXT_PROCESSORS=[
+ 'django.core.context_processors.media',
+ 'django.core.context_processors.static',
+ ],
TEMPLATE_LOADERS=['django.template.loaders.filesystem.Loader'],
TEMPLATE_DIRS=[os.path.join(os.path.dirname(__file__),
'_testproject', 'templates')],
@@ -151,7 +157,7 @@ class TestViews(TestCase):
self.assertTrue(pdf_content.startswith('%PDF-'))
self.assertTrue(pdf_content.endswith('%%EOF\n'))
- # Header
+ # Footer
filename = 'output.pdf'
footer_template = 'footer.html'
cmd_options = {'title': 'Test PDF'}
@@ -170,20 +176,53 @@ class TestViews(TestCase):
tempfile = response.render_to_temporary_file(footer_template)
tempfile.seek(0)
footer_content = tempfile.read()
- self.assertTrue('MEDIA_URL = {}'.format(settings.MEDIA_URL)
- in footer_content)
- self.assertTrue('STATIC_URL = {}'.format(settings.STATIC_URL)
- in footer_content)
+
+ media_url = 'MEDIA_URL = file://{}/'.format(settings.MEDIA_ROOT)
+ self.assertTrue(
+ media_url in footer_content,
+ "{!r} not in {!r}".format(media_url, footer_content)
+ )
+
+ static_url = 'STATIC_URL = file://{}/'.format(settings.STATIC_ROOT)
+ self.assertTrue(
+ static_url in footer_content,
+ "{!r} not in {!r}".format(static_url, footer_content)
+ )
pdf_content = response.rendered_content
self.assertTrue('\0'.join('{title}'.format(**cmd_options))
in pdf_content)
+ # Override settings
+ response = PDFTemplateResponse(request=request,
+ template=template,
+ context=context,
+ filename=filename,
+ footer_template=footer_template,
+ cmd_options=cmd_options,
+ override_settings={
+ 'STATIC_URL': 'file:///tmp/s/'
+ })
+ tempfile = response.render_to_temporary_file(footer_template)
+ tempfile.seek(0)
+ footer_content = tempfile.read()
+
+ static_url = 'STATIC_URL = {}'.format('file:///tmp/s/')
+ self.assertTrue(
+ static_url in footer_content,
+ "{!r} not in {!r}".format(static_url, footer_content)
+ )
+ self.assertEqual(settings.STATIC_URL, '/static/')
+
def test_pdf_template_view(self):
"""Test PDFTemplateView."""
with override_settings(
MEDIA_URL='/media/',
STATIC_URL='/static/',
+ TEMPLATE_CONTEXT_PROCESSORS=[
+ 'django.core.context_processors.media',
+ 'django.core.context_processors.static',
+ ],
TEMPLATE_LOADERS=['django.template.loaders.filesystem.Loader'],
TEMPLATE_DIRS=[os.path.join(os.path.dirname(__file__),
'_testproject', 'templates')],
@@ -193,7 +232,8 @@ class TestViews(TestCase):
template = 'sample.html'
filename = 'output.pdf'
view = PDFTemplateView.as_view(filename=filename,
- template_name=template)
+ template_name=template,
+ footer_template='footer.html')
# As PDF
request = RequestFactory().get('/')
diff --git a/wkhtmltopdf/utils.py b/wkhtmltopdf/utils.py
index 03a5f82..69da74f 100644
--- a/wkhtmltopdf/utils.py
+++ b/wkhtmltopdf/utils.py
@@ -5,6 +5,7 @@ from itertools import chain
from os import fdopen
import sys
from tempfile import mkstemp
+import urllib
import warnings
from django.conf import settings
@@ -124,6 +125,11 @@ def http_quote(string):
return '"{!s}"'.format(string.replace('\\', '\\\\').replace('"', '\\"'))
+def pathname2fileurl(pathname):
+ """Returns a file:// URL for pathname. Handles OS-specific conversions."""
+ return 'file://' + urllib.pathname2url(pathname)
+
+
try:
# From Django 1.4
from django.conf import override_settings
diff --git a/wkhtmltopdf/views.py b/wkhtmltopdf/views.py
index c337b6c..4bceb27 100644
--- a/wkhtmltopdf/views.py
+++ b/wkhtmltopdf/views.py
@@ -5,12 +5,12 @@ 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.response import TemplateResponse
from django.views.generic import TemplateView
-from .utils import (content_disposition_filename, wkhtmltopdf)
+from .utils import (content_disposition_filename, override_settings,
+ pathname2fileurl, wkhtmltopdf)
class PDFResponse(HttpResponse):
@@ -51,7 +51,8 @@ class PDFTemplateResponse(TemplateResponse, PDFResponse):
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):
+ cmd_options=None, override_settings=None,
+ *args, **kwargs):
super(PDFTemplateResponse, self).__init__(request=request,
template=template,
@@ -70,12 +71,23 @@ class PDFTemplateResponse(TemplateResponse, PDFResponse):
cmd_options = {}
self.cmd_options = cmd_options
+ self.override_settings = override_settings
+
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)
+
+ # Since many things require a sensible settings.MEDIA_URL and
+ # settings.STATIC_URL, including TEMPLATE_CONTEXT_PROCESSORS;
+ # the settings themselves need to be overridden when rendering.
+ #
+ # This allows django-wkhtmltopdf to play nicely with the
+ # staticfiles app, for instance.
+ with override_settings(**self.get_override_settings()):
+ 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)
@@ -132,6 +144,31 @@ class PDFTemplateResponse(TemplateResponse, PDFResponse):
for f in filter(None, (input_file, header_file, footer_file)):
f.close()
+ def get_override_settings(self):
+ """Returns a dictionary of settings to override for response_class"""
+ overrides = {
+ 'MEDIA_ROOT': settings.MEDIA_ROOT,
+ 'MEDIA_URL': settings.MEDIA_URL,
+ 'STATIC_ROOT': settings.STATIC_ROOT,
+ 'STATIC_URL': settings.STATIC_URL,
+ }
+ if self.override_settings is not None:
+ overrides.update(self.override_settings)
+
+ has_scheme = compile(r'^[^:/]+://')
+
+ # If MEDIA_URL doesn't have a scheme, we transform it into a
+ # file:// URL based on MEDIA_ROOT.
+ urls = [('MEDIA_URL', 'MEDIA_ROOT'),
+ ('STATIC_URL', 'STATIC_ROOT')]
+ for url, root in urls:
+ if not has_scheme.match(overrides[url]):
+ overrides[url] = pathname2fileurl(overrides[root])
+ if not overrides[url].endswith('/'):
+ overrides[url] += '/'
+
+ return overrides
+
class PDFTemplateView(TemplateView):
"""Class-based view for HTML templates rendered to PDF."""
@@ -184,34 +221,26 @@ class PDFTemplateView(TemplateView):
PendingDeprecationWarning, 2)
return self.get_cmd_options()
- def get_context_data(self, **kwargs):
- context = super(PDFTemplateView, self).get_context_data(**kwargs)
-
- match_full_url = compile(r'^https?://')
- if not match_full_url.match(settings.STATIC_URL):
- context['STATIC_URL'] = 'http://' + Site.objects.get_current().domain + settings.STATIC_URL
- if not match_full_url.match(settings.MEDIA_URL):
- context['MEDIA_URL'] = 'http://' + Site.objects.get_current().domain + settings.MEDIA_URL
-
- 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', None)
cmd_options = response_kwargs.pop('cmd_options', None)
+ override_settings = response_kwargs.pop('override_settings', 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,
header_template=self.header_template,
footer_template=self.footer_template,
- cmd_options=cmd_options,
+ cmd_options=cmd_options, override_settings=override_settings,
**response_kwargs
)
else: