It's been far too long since my last post. A lot has happened and the holidays make things so busy but I'm back and ready to get back in to the swing of things. To start off the new year I'm going to do a series of posts relating to ReportLab specifically with its application to Django. I want to go over a few of the pitfalls I've experienced and how to get things set up. ReportLab is notoriously tricky to get working and the documentation seems sparse to say the least. I hope these posts help not only myself remeber how I did all of this but others who are struggling with the same problems.
pip install reportlab. The first thing to do is get a robust class set up for doing all of your printing. I created a printing.py file that houses all of my basic ReportLab set up and functions. Branching off from there I have my individual pages and paperwork that get combined and output to the user. Let's start with a simple printing.py file.
As you can see my class is very simple. I pass in a buffer to house my data that will be returned to the user, I'll show this once we get set up, and a page size. ReportLab has a lot of built in page sizes but you can even set your own if you'd like by using your own width and height variables.
from reportlab.lib.pagesizes import letter, A4
class MyPrint: def init(self, buffer, pagesize): self.buffer = buffer if pagesize == 'A4': self.pagesize = A4 elif pagesize == 'Letter': self.pagesize = letter self.width, self.height = self.pagesize
from reportlab.platypus import SimpleDocTemplate, Paragraph from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER from django.contrib.auth.models import UserThe code is commented nicely but let's walk through it. We start by taking our buffer and putting it into what is a SimpleDocTemplate. This is a ReportLab object that will generate a PDF with some standard values. There are a ton of customizations you can make and even create your own document templates but for now let's stick with the simple. We set the margins for the page and the page size. You can use inches or millimeters too if you'd like, ReportLab has a few built in measurement sizes that just need to be imported.
def print_users(self): buffer = self.buffer doc = SimpleDocTemplate(buffer, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=72, pagesize=self.pagesize)
# Our container for 'Flowable' objects elements =  # A large collection of style sheets pre-made for us styles = getSampleStyleSheet() styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER)) # Draw things on the PDF. Here's where the PDF generation happens. # See the ReportLab documentation for the full list of functionality. users = User.objects.all() elements.append(Paragraph('My User Names', styles['Heading1'])) for i, user in enumerate(users): elements.append(Paragraph(user.get_full_name(), styles['Normal'])) doc.build(elements) # Get the value of the BytesIO buffer and write it to the response. pdf = buffer.getvalue() buffer.close() return pdf
Next we have a list of elements. This list will hold all of the ReportLab Flowables that will be generated on the PDF itself. A Flowable is an object that has space and size on a PDF. This can be a block of text, a table, an image, or you can even create a custom Flowable. Whatever we put in this list will be generated in order on our PDF.
After that you'll see some styles that we use. These styles are going to be used for various elements like Paragraph styling. After we get the style sheets I've added a new one that simply centers text and nothing more.
Now we come to the part where we are going to add elements to our document to be rendered. I've used Django to grab my list of users and I loop through them one at a time to add their name to a Paragraph flowable. A Paragraph flowable will take up the entire width of the area you give it. In our case we have not confied the Paragraph to the inside of a table or to a column so each Paragraph will fill in the entire width of the document.
Once we have added all of our elements we simply build the doc. This renders the PDF and places all PDF data into that buffer we gave the doc when we initiated it. Close the buffer for good practice and return the contents of the PDF to the user. Simple enough. To run all of the code that I have shown I have a view in my views.py file that will run all of this and you can see how to access the printing.py class and method and output your PDF to your users.
from myapp.printing import MyPrint from io import BytesIO @staff_member_required def print_users(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="My Users.pdf"' buffer = BytesIO() report = MyPrint(buffer, 'Letter') pdf = report.print_users() response.write(pdf) return response
That's all there is to it. I hope this was enlightening on at least how to get started. Next time I will explain how to add headers and footers to your documents as well as a surprisingly tricky to find way of adding page numbers.
If you have anything you'd like to learn about for ReportLab and Django please leave a comment below.