[Fixed]-Creating PDFs with django (wkhtmltopdf)

26👍

The difference between PDFTemplateView and PDFTemplateResponse is that the view is a class-based view. And PDFTemplateResponse renders the pdf data and sets the right response headers. To add header and footer:

# urls.py

from django.conf.urls.defaults import *
from wkhtmltopdf.views import PDFTemplateView


    urlpatterns = patterns('',
        ...
        url(r'^pdf/$', PDFTemplateView.as_view(template_name='my_template.html',
                filename='my_pdf.pdf', 
                header_template='my_header_template.html', 
                footer_template='my_footer_template.html', 
                ...
                ), name='pdf'),
    )

Opening pdf/ in your browser will start a download of my_pdf.pdf based on the my_template.html, my_header_template.html and my_footer_template.html.

The advanced example shows how to subclass PDFTemplateView extending and changing the logic of PDFTemplateView. To understand what happens read Using class based views.

Like header_template and footer_template you can define a response_class. Because PDFTemplateResponse is the default, you don’t have to define it.

EDIT

The following simple view provides you with a pdf instead of an html. This is not using django-wkhtmltopdf. You could use wkhtmltopdf in your html2pdf function.

def some_view(request):
    t = loader.get_template('myapp/template.html')
    c = RequestContext(request, {'foo': 'bar'})
    html = t.render(c)
    pdf_data = html2pdf(html) # Your favorite html2pdf generator
    response = HttpResponse(pdf_data, content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="some_filename.pdf"'
    return response

EDIT 2

A simple view with context:

template.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Untitled</title>
</head>
<body>
    <h1>{{ title }}</h1>
</body>
</html>

urls.py

from views import MyPDFView

urlpatterns = patterns('',
    (r'^pdf/', MyPDFView.as_view()),
)

views.py

from django.views.generic.base import View
from wkhtmltopdf.views import PDFTemplateResponse

class MyPDFView(View):
    template='template.html'
    context= {'title': 'Hello World!'}

    def get(self, request):
        response = PDFTemplateResponse(request=request,
                                       template=self.template,
                                       filename="hello.pdf",
                                       context= self.context,
                                       show_content_in_browser=False,
                                       cmd_options={'margin-top': 50,},
                                       )
        return response

EDIT 3

If you use a DetailView, you can add the object to context:

url(r'^books/(?P<pk>\d+)/$', MyPDFView.as_view(), name='book-detail'),


class MyPDFView(DetailView):
    template='pdftestapp/template.html'    
    context= {'title': 'Hello World!'}
    model = Book

    def get(self, request, *args, **kwargs):        
        self.context['book'] = self.get_object()

        response=PDFTemplateResponse(request=request,
                                     template=self.template,
                                     filename ="hello.pdf",
                                     context=self.context,
                                     show_content_in_browser=False,
                                     cmd_options={'margin-top': 50,}
                                     )
        return response

2👍

Hmm the error indicates that you’re passing string somewhere that you shouldn’t.

After checking its source code, I guess in settings.py you have WKHTMLTOPDF_CMD_OPTIONS as a string, something like

WKHTMLTOPDF_CMD_OPTIONS = 'some_option_here'

But you should assign a dict there:

WKHTMLTOPDF_CMD_OPTIONS = {
    'quiet': True,
}

Otherwise your code should work fine.

Leave a comment