Django PDF rendering¶
Django PDF rendering, the easy way.
Developed at en.ig.ma software shop.
Overview¶
This app makes rendering PDF files in Django really easy. It can be used to create invoices, bills and other documents from simple HTML markup and CSS styles. You can even embed images and use custom fonts.
The library provides both Class-Based View that is almost a drop-in
replacement for Django’s TemplateView
as well as helper functions
to render PDFs in the backend outside the request scope
(i.e. using Celery workers).
Quickstart¶
Include
django-easy-pdf>=0.2.0
andWeasyPrint>=0.34
in yourrequirements.txt
file and install necessary system packages.Add
easy_pdf
toINSTALLED_APPS
.Create HTML template for PDF document and add a view that will render it:
{% extends "easy_pdf/base.html" %} {% block content %} <div id="content"> <h1>Hi there!</h1> </div> {% endblock %}
from easy_pdf.views import PDFTemplateView class HelloPDFView(PDFTemplateView): template_name = 'hello.html'
You can also use a mixin to output PDF from Django generic views:
class PDFUserDetailView(PDFTemplateResponseMixin, DetailView): model = get_user_model() template_name = 'user_detail.html'
Documentation¶
The full documentation is at django-easy-pdf.readthedocs.io.
A live demo is at easy-pdf.herokuapp.com.
You can run it locally after installing dependencies by running python demo.py
script from the cloned repository or through Docker with make demo
.
Dependencies¶
django-easy-pdf
depends on:
django>=1.10
WeasyPrint>=0.34
WeasyPrint
dependencies (https://weasyprint.readthedocs.io/en/latest/install.html)
License¶
django-easy-pdf
is released under the MIT license.
Other Resources¶
- GitHub repository - https://github.com/nigma/django-easy-pdf
- PyPi Package site - https://pypi.python.org/pypi/django-easy-pdf
- Docs - https://django-easy-pdf.readthedocs.io/en/develop/
Commercial Support¶
This app and many other help us build better software and focus on delivering quality projects faster. We would love to help you with your next project so get in touch by dropping an email at en@ig.ma.
Content¶
Installation¶
Add
django-easy-pdf==0.2.0
andWeasyPrint>=0.34
to yourrequirements.txt
file or install it directly from the command line by invoking:$ pip install -U django-easy-pdf WeasyPrint
Install WeasyPrint system dependencies specific to your platform.
On Debian/Ubuntu install:
apt-get install -y --no-install-recommends gettext libcairo2 libffi-dev libpango1.0-0 \ libgdk-pixbuf2.0-0 libxml2-dev libxslt1-dev shared-mime-info
For install instructions on other platforms see http://weasyprint.readthedocs.io/en/latest/install.html.
If you are using Docker to deploy your application you can consult the included Dockerfile for complete setup instructions.
Usage¶
Prepare HTML Templates¶
Create a Django HTML template with embedded CSS style. You can use special style attributes to format the PDF output.
For more information on the supported HTML and CSS rules see docs at https://weasyprint.readthedocs.io/en/latest/features.html
You can also use custom embeddable resources like images and fonts.
They can be referenced locally via the file://
protocol or fetched
from web over http://
or https://
.
{% extends "easy_pdf/base.html" %}
{% block extra_style %}
<style type="text/css">
body {
font-family: "Helvetica", "sans-serif";
color: #333333;
}
</style>
{% endblock %}
{% block content %}
<div id="content">
<div class="main">
<h1>Hi there!</h1>
<img src="file:///STATIC_ROOT/img/hello.png" />
</div>
</div>
{% endblock %}
Create PDF rendering views¶
This part is easy. The PDF rendering view inherits from
TemplateResponseMixin
so it works in the same way as Django’s
TemplateView
.
Just point it to a HTML template and define
get_context_data()
method to pass any extra variables to the template:
from django.conf import settings
from easy_pdf.views import PDFTemplateView
class HelloPDFView(PDFTemplateView):
template_name = 'hello.html'
base_url = 'file://' + settings.STATIC_ROOT
download_filename = 'hello.pdf'
def get_context_data(self, **kwargs):
return super(HelloPDFView, self).get_context_data(
pagesize='A4',
title='Hi there!',
**kwargs
)
Notice the base_url
attribute that can be used to specify base URL for
all files referenced in the template by relative URLs.
Then add the view to your url config and start serving PDF files rendered from the HTML template.
urlpatterns = [
url(r'^hello.pdf$', HelloPDFView.as_view())
]
You can also use a mixin to output PDF from Django generic views:
.. code-block:: python
- class PDFUserDetailView(PDFTemplateResponseMixin, DetailView):
- model = get_user_model() template_name = ‘user_detail.html’
Rendering PDF outside of Django views¶
API Overview¶
Views¶
PDFTemplateResponseMixin¶
-
class
easy_pdf.views.
PDFTemplateResponseMixin
¶ Bases:
django.views.generic.base.TemplateResponseMixin
A mixin class that implements PDF rendering and Django response construction.
-
download_filename
= None¶ Optional name of the PDF file for download. Leave blank for display in browser.
-
base_url
= None¶ Base URL for referencing relative images, fonts and stylesheet resources.
-
response_class
¶ Response class. Defaults to
django.http.HttpResponse
.alias of
HttpResponse
-
content_type
= 'application/pdf'¶ Response content type. Default is
'application/pdf'
.
-
get_download_filename
()¶ Returns
download_filename
value by default.If left blank the browser will display the PDF inline. Otherwise it will pop up the “Save as..” dialog.
Return type: str
or None
-
get_render_kwargs
()¶ The render kwargs are passed to
html_to_pdf()
.
-
get_pdf_response
(context)¶ Renders PDF document and prepares response.
Returns: Django HTTP response Return type: django.http.HttpResponse
-
render_to_response
(context, **response_kwargs)¶
-
PDFTemplateView¶
-
class
easy_pdf.views.
PDFTemplateView
(**kwargs)¶ Bases:
easy_pdf.views.PDFTemplateResponseMixin
,django.views.generic.base.ContextMixin
,django.views.generic.base.View
A view that renders template to PDF document in a way similar to Django’s
TemplateView
class HelloPDFView(PDFTemplateView): template_name = "hello.html"
-
get
(request, *args, **kwargs)¶ Handles GET request and returns HTTP response.
-
PDF rendering functions¶
-
easy_pdf.rendering.
render_to_pdf
(template, context, using=None, request=None, **render_kwargs)¶ Creates PDF document from Django HTML template.
Parameters: Return type: Returns: Rendered PDF document
Additional
**render_kwargs
are passed tohtml_to_pdf()
.
-
easy_pdf.rendering.
render_to_pdf_response
(request, template, context, using=None, download_filename=None, content_type='application/pdf', response_class=HttpResponse, **render_kwargs)¶ Renders a PDF response using given
request
,template
andcontext
.If
download_filename
param is specified then the responseContent-Disposition
header will be set toattachment
making the browser display a “Save as..” dialog.Parameters: - request (
django.http.HttpRequest
) – Django HTTP request - template (str) – Path to Django template
- context (dict) – Template context
- using – Optional Django template engine
- download_filename (str) – Optional filename to use for file download
- content_type (str) – Response content type
- response_class – Default is
django.http.HttpResponse
Return type: Returns: Django HTTP response
Additional
**render_kwargs
are passed tohtml_to_pdf()
.- request (
-
easy_pdf.rendering.
render_to_content_file
(template, context, using=None, **render_kwargs)¶ Example:
>>> content = render_to_content_file('doc.html')
Then save to Django storage:
>>> from django.core.files.storage import default_storage >>> default_storage.save('file.pdf', content)
Or attach to a model instance:
>>> instance.attachment.save('file.pdf', content, save=True)
Parameters: - template (str) – Path to Django template
- context (
dict
ordjango.template.Context
) – Template context - using – Optional Django template engine
Return type: Returns: Django content file
Additional
**render_kwargs
are passed tohtml_to_pdf()
.
Other lower-level helpers¶
-
easy_pdf.rendering.
html_to_pdf
(content, stylesheets=None, base_url=None, url_fetcher=default_url_fetcher, media_type='print')¶ Converts HTML
content
into PDF document.The HTML document can contain references to image, font and style resources provided as absolute or relative URLs. If resources are referenced by relative URLs the
base_url
param must also be specified so theurl_fetcher
is able to load the files.Resource URLs can use either external
http://
orhttps://
protocol or localfile://
protocol (for example when embedding images fromSTATIC_ROOT
directory).Keep that in mind and always specify and validate URLs for linked resources in case of user generated content is rendered to PDF documents to avoid potential security issues.
Parameters: - content (str) – HTML content to render
- stylesheets (list of
weasyprint.CSS
orNone
) – Additionalweasyprint.CSS
stylesheets orNone
. See https://weasyprint.readthedocs.io/en/latest/tutorial.html#stylesheet-origins. - base_url – The base used to resolve relative URLs. See WeasyPrint docs.
- url_fetcher – A function or other callable with the same signature
as
weasyprint.default_url_fetcher()
called to fetch external resources such as stylesheets and images. See https://weasyprint.readthedocs.io/en/latest/tutorial.html#url-fetchers. - media_type – The media type to use for
@media
. Defaults to'print'
.
Return type: Returns: PDF content
-
easy_pdf.rendering.
make_response
(content, download_filename=None, content_type='application/pdf', response_class=HttpResponse)¶ Wraps file content into HTTP response.
If
filename
is specified thenContent-Disposition: attachment
header is added to the response.Default
Content-Type
is'application/pdf'
.Parameters: Return type: Returns: Django response
-
easy_pdf.rendering.
encode_filename
(filename)¶ Encodes filename part for
Content-Disposition: attachment
.Parameters: filename (str) – Filename to encode Return type: str Returns: Encoded filename for use in Content-Disposition
header>>> print(encode_filename("abc.pdf")) filename=abc.pdf >>> print(encode_filename("aa bb.pdf")) filename*=UTF-8''aa%20bb.pdf >>> print(encode_filename(u"zażółć.pdf")) filename*=UTF-8''za%C5%BC%C3%B3%C5%82%C4%87.pdf
Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/nigma/django-easy-pdf/issues.
If you are reporting a bug, please include:
- Your operating system name and version.
- Any details about your local setup that might be helpful in troubleshooting.
- Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “feature” is open to whoever wants to implement it.
Write Documentation¶
django-easy-pdf could always use more documentation, whether as part of the official django-easy-pdf docs, in docstrings, or even on the web in blog posts, articles, and such.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/nigma/django-easy-pdf/issues.
If you are proposing a feature:
- Explain in detail how it would work.
- Keep the scope as narrow as possible, to make it easier to implement.
- Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up django-easy-pdf for local development.
Fork the django-easy-pdf repo on GitHub.
Clone your fork locally:
$ git clone git@github.com:your_name_here/django-easy-pdf.git
Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:
$ mkvirtualenv django-easy-pdf $ cd django-easy-pdf/ $ python setup.py develop
Create a branch for local development:
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
When you’re done making changes, check that your changes pass flake8:
$ flake8 easy_pdf
To get flake8, just pip install them into your virtualenv.
Commit your changes and push your branch to GitHub:
$ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature
Submit a pull request through the GitHub website.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
- If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
- The pull request should work for Python 2.7, and 3.4+ (if there are compatible 3rd party packages available). Check https://travis-ci.org/nigma/django-easy-pdf/pull_requests and make sure that the tests pass for all supported Python versions.