2

I am trying to convert my HTML to a PDF. I watched this tutorial, https://www.codingforentrepreneurs.com/blog/html-template-to-pdf-in-django/ and I was able to successfully get the tutorial to work with hardcoded values. The problem is...I can't figure out how to dynamically incorporate my model and it's attributes into this example.

Here are the steps I followed...

First I installed reportlab into my environment with the following version...

pip install --pre xhtml2pdf 

This worked...

Then I added a utils.py file to my project as instructed.

Then I copied this code into my utils.py file...

from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template

from xhtml2pdf import pisa

def render_to_pdf(template_src, context_dict={}):
    template = get_template(template_src)
    html  = template.render(context_dict)
    result = BytesIO()
    pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
    if not pdf.err:
        return HttpResponse(result.getvalue(), content_type='application/pdf')
    return None

Then I created an HTML file like the one below:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>Title</title>
        <style type="text/css">
            body {
                font-weight: 200;
                font-size: 14px;
            }
            .header {
                font-size: 20px;
                font-weight: 100;
                text-align: center;
                color: #007cae;
            }
            .title {
                font-size: 22px;
                font-weight: 100;
               /* text-align: right;*/
               padding: 10px 20px 0px 20px;  
            }
            .title span {
                color: #007cae;
            }
            .details {
                padding: 10px 20px 0px 20px;
                text-align: left !important;
                /*margin-left: 40%;*/
            }
            .hrItem {
                border: none;
                height: 1px;
                /* Set the hr color */
                color: #333; /* old IE */
                background-color: #fff; /* Modern Browsers */
            }
        </style>
    </head>
    <body>
        <div class='wrapper'>
            <div class='header'>
                <p class='title'>Invoice # </p>
            </div>
        <div>
        <div class='details'>
            Bill to: {{ customer_name }} <br/>
            Amount: {{ amount }} <br/>
            Date: 
            <hr class='hrItem' />
        </div>
    </div>
    </body>
</html>

I also created the necessary URL....

Then I created a view similar to what is defined below:

from django.http import HttpResponse
from django.views.generic import View

from yourproject.utils import render_to_pdf #created in step 4

class GeneratePdf(View):
    def get(self, request, *args, **kwargs):
        data = {
             'today': datetime.date.today(), 
             'amount': 39.99,
            'customer_name': 'Cooper Mann',
            'order_id': 1233434,
        }
        pdf = render_to_pdf('pdf/invoice.html', data)
        return HttpResponse(pdf, content_type='application/pdf')

When I click on my link to this view...the output shows just like the tutorial says...

However, if I am trying to get my model to display in this format...I'm stumped as to how to do that. I tried a DetailView....and then I get the data but no PDF....I've also searched many other places and I can't seem to find an example that would allow me to get my model dynamically and pull in attributes as needed...Thanks in advance for any help or pointers.

Steve Smith
  • 1,019
  • 3
  • 16
  • 38

1 Answers1

6

If you want to use DetailView, I think you can do it like this:

class SomeDetailView(DetailView):
    model = YourModel
    template_name = 'pdf/invoice.html'

    def get_context_data(self, **kwargs):
        context = super(SomeDetailView, self).get_context_data(**kwargs)
        # add extra context if needed
        return context

    def render_to_response(self, context, **kwargs):
        pdf = render_to_pdf(self.template_name, context)
        return HttpResponse(pdf, content_type='application/pdf')

Here I am overriding render_to_response to override the default response from DetailView to return a PDF response. Here, the context that comes in are from get_context_data. in get_context_data you can add any extra context if needed.

ruddra
  • 50,746
  • 7
  • 78
  • 101
  • Would be super if possible to generalize above answer to RL (as in heading) (xhtml2pdf is used here)? In essence, how would you successfully be able to pass that context and connect it to variables in non html template (RL uses (global) variables) e.g. as above Data = {'amount': 39.99, '-----etc ,} It is explained that a Model holds the Data and we retrieve this context data but not how we transport that context further in RL. Assume the non-html template has variables such as 'Amount', how do you assign 39.99 from your context to the non-html RL template before print pdf? – Jaco Feb 07 '19 at 19:37
  • @ruddra i am using this method also when creating my pdfs using a Class Based View, but i am facing a problem,i am not able to show up my current logged user into my pdf, i've been using the {%if user.is_authenticated%} tags but when rendering into the pdf there is no information showing up, like if the condition has not been fullfilled! is there any extra data i need to add to the get_context_data method? or is this any default behavior of the pdf rendering? – Luis Rodriguez Jun 02 '20 at 04:45
  • Can you please ask a new question regarding this with more coding detail? Honestly I am out of context with reportlab at the moment, but I am sure someone else can help you regarding this issue. – ruddra Jun 02 '20 at 05:07