Giter Site home page Giter Site logo

django-easy-pdf's Introduction

Django PDF rendering

Django PDF rendering, the easy way.

Build Status Latest Version Wheel License

Developed at en.ig.ma software shop.

Development Version

Note: A new PDF rendering backend using WeasyPrint for more accurate rendering is in development under the develop branch. See #34 for changes, testing and discussion.

If you rely on the xhtml2pdf rendering backend and templates pin the package version to django-easy-pdf>=0.1.1<0.2.0.

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

  1. Include django-easy-pdf, xhtml2pdf in your requirements.txt file. If you are on Python 3 you need to install the latest version of Reportlab and the beta version of xhtml2pdf:

    $ pip install xhtml2pdf>=0.2b1
    
  2. Add easy_pdf to INSTALLED_APPS.

  3. 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'
  4. 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
  • xhtml2pdf>=0.2b1
  • reportlab

License

django-easy-pdf is released under the MIT license.

Other Resources

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 [email protected].

django-easy-pdf's People

Contributors

metakermit avatar msaizar avatar nigma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-easy-pdf's Issues

Support with Jingo

When rendering with Jingo it crashes with this error:

ValueError at /my/url

dictionary update sequence element #0 has length 12; 2 is required

Fix context request

Hello, in line 81 of views.py you have to add
self.request = request

because if you don't, generate error on line 55.

compatible with python 3.6

Will this work in python3.6 and can I be able to add my context data. I think I tried this and did not work but its been a while so I'm gonna give it another try.

Allow files to be named and displayed on the screen

The way the app works right now is that you either set a nice filename or you leave it blank and the pdf displays on the screen. Can we add a flag like show_content_in_browser which will allow the dev to set a nice filename and display on the screen at the same time.

I am willing to add this myself if the project admin(s) are interested. Please let me know.

Conditional PDF rendering based on query parameters

Hello there 👋,

I want to propose a new feature.

Use case

I have a view that recently 'got converted' to PDFTemplateView but that view only works for a few scenarios. There is still and scenario where I need the view to be a plain HTML response. Being able to configure PDFTemplateView to render the view as a PDF file based on some configured query parameter comes in handy to achieve such behavior.

Say for example I have a view at the endpoint /invoices/123. The idea is that if I fetch /invoices/123 it returns a plain HTML response. But if I fetch /invoices/123?pdf or /invoices/123?format=pdf the PDFTemplateView will do its job.

Of course this would break the existing behavior but we can make it work without the need to make a major version bump.

Implementation

Taking into consideration backwards compatibility as the most important aspect I was thinking that we should add an extra view property (and its corresponding get method)

...


class MyAwesomeView(DetailView, PDFTemplateResponseMixin):
    model = ....
    trigger = 'pdf' # Naming it's not my strength

    # or
    def get_trigger(self): # Again, naming...
        return 'pdf'

This way, existing implementations that do not include a trigger option will behave exactly the same as a None value for trigger would normally render the view as a PDF file.

PR

I already went ahead and forked the repo to start working on this. Any comment or thought will be appreciated. And If anyone can come with a better naming for the class' property I will highly grateful 😅

How to add images in pdf ?

from easy_pdf.rendering import render_to_pdf_response

def performance_pdf(request):
    data = {}
    return render_to_pdf_response(request, 'report/report-base.html', data)

I want this image include in generated pdf but below method not working.

<!DOCTYPE html>
<html>
<head>
    <title>{{ title|default:"" }}</title>
        <style type="text/css">
            body {
                background: white url("https://www.htgmanager.org/common/images/html_background.jpg") no-repeat right bottom;
            }
        </style>
</head>
<body>
</body>
</html>

'ascii' codec can't encode characters in position 11-14: ordinal not in range(128)

Hi guys,

I managed so far to get this package working for xhtml2pdf==0.0.5. For newer version, I get the following error in xhtml2pdf. The decoding of the rendered pdf text (value) seems to be the problem. This is as far as my assessment went. It would be nice if easy-pdf would also work for the newer version of xhtml2pdf.

cheers,
Besma

@page pseudo classes don't work

Pseudo classes for @page don't work.

{% block extra_style %}
    <style type="text/css">
        @page {
            color: black;
        }
        @page :first {
            color:red;
        }
    </style>
{% endblock %}

It raises TypeError:

TypeError: unsupported operand type(s) for +: 'NoneType' and 'str' at xhtml2pdf/w3c/cssParser.py in _parseAtPage, line 726

Any ideas for workaround?

Bootstrap

Is the default styling bootstrap compatible ?
I included bootstrap styling in extra_styles block but it doesn't seem to work.

DEFAULT_CSS overriding embedded styles

It seems that for some reason the dafault styling found here is overriding custom styles in the layout_style and extra_style blocks.

If I for example want to change the font-size for headings, this works:

{% block extra_style %}
    <style>
        h4 { font-size: 20pt; }
    </style>
{% endblock %}

But this doesnt:

{% block extra_style %}
    <style>
        h1,h2,h3 { font-size: 20pt; }
    </style>
{% endblock %}

I assume this is because font-size is already set for h1,h2,h3 in DEFAULT_CSS but not for h4. Shouldn't styles in extra_style override styles set in DEFAULT_CSS?

WARNING: There are known rendering problems with Cairo <= 1.14.0

The dependencies listed in the dockerfile:

 DEPS=' \
        bash \
        gettext \
        libcairo2 \
        libffi-dev \
        libpango1.0-0 \
        libpangoft2-1.0-0 \
        libgdk-pixbuf2.0-0 \
        libxml2-dev \
        libxslt1-dev \
        shared-mime-info \
        fontconfig \
        libfontconfig1 \
    ' \

Are causing the following warning messages:

WARNING: There are known rendering problems with Cairo <= 1.14.0
WARNING: @font-face is currently not supported on Windows

Everything is working fine but maybe we should change the dependencies to a newer version?

P.S: can't wait for 0.2.0 release, great work! this library is definitely the less painful of all those that I have found (django-wkhtmltopdf, reportlab)

-pdf-frame-content to frame header not working

I'm using this css to set a header and foot to my layout. For some reason the content block is being rendered in the very beginning of the page. So the header is being renderer over the initial part of content.

Here is the code.

{% extends "easy_pdf/base.html" %}
{% load staticfiles %}
{% load widget_tweaks %}

{% block layout_style %}
    <style type="text/css">
        @page {
            size: {{ pagesize|default:"A4" }};
            margin-left: 5.5cm;
            margin-right: 2.5cm;
            margin-top: 2.5cm;
            margin-bottom: 2cm;

            @frame header {
                -pdf-frame-content: page-header;
                margin-top: 1.3cm;
                margin-right: 2mm;
                margin-bottom: 1cm;
                margin-left: 1.2cm;
                height : 30px;
                border: 1px solid red;
            }

            @frame footer {
                -pdf-frame-content: page-footer;
                bottom: 0cm;
                margin-left: 1cm;
                margin-right: 1cm;
                height: 1cm;
            }

        }
    </style>
{% endblock %}

{% block extra_style %}
    <style type="text/css">
        span > * {
            text-decoration: underline;
            text-decoration-color: red;
        }
        #pager-header{
            border:1pt solid red;
        }
    </style>
{% endblock %}

{%block page_header%}
    <div id="page-header">
        <div class="header">
            <p>
                Street Name <br>
                Postal Code <br/>
                City
            </p>
            <p class="header-link">
                <a class="header-link" href="http://en.ig.ma/">en.ig.ma</a>
            </p>
        </div>
    </div>
{% endblock %}

{% block content %}

{% include "api/template1.html" %}

{% for item in somearray1 %}
    {% if item.somearray2 %}
        <br>
        <table border="1" cellpadding="5" class="table table-bordered">
                <tr>
                    <td align="left" valign="center" colspan="5">
                        <h4>HEader</h4>
                    </td>
                </tr>
                <tr>
                    <td> ... </td>
                </tr>

                {% for evd in item.evolucao %}
                <tr>
                    <td> ... </td>
                </tr>
                {% endfor %}

        </table>
    {% endif %}
{% endfor %}
{% endblock %}

Cache?

My Class / View looks like this:

class letterView(PDFTemplateView):

    def get_context_data(self, **kwargs):
        letterID = self.kwargs['letterID']
        object = get_object_or_404(djangoLetters, id=letterID)
        return super(letterView, self).get_context_data(object=object, **kwargs)

    def get_template_names(self):
        letterID = self.kwargs['letterID']
        letterType = djangoLetters.objects.get(pk=letterID).letterType
        template_name = str(letterType.letterBackgroundBase).strip()
        # template_name = str("letter.html")
        return [template_name]

Anyone know where I can specify to never cache the pdf on return? I don't see it in the documentation and can't do it on the get_context_data/get_template_names views.

@never_cache declaration was what I was going to use.

How to import image with PDFTemplateResponseMixin

Hello,

The image does not load on my PDF.
Here is the views.py

from easy_pdf.views import PDFTemplateResponseMixin
from django.conf import settings

class PostPDFDetailView(PDFTemplateResponseMixin,DetailView):
    model = models.Post
    template_name = 'post/post_pdf.html'

    base_url = 'file://' + settings.STATIC_ROOT

    def get_context_data(self, **kwargs):
        return super(PostPDFDetailView, self).get_context_data(
            pagesize='A4',
            **kwargs
        )

Here the PDF template, post_pdf.html

{% load static from staticfiles %}
{% load simulation_extras %}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <div id="container">
        <img src="file:///STATIC_ROOT/images/logo-home.png"/>
    </div>
</body>
</html>

template.render( request_context vs. dict)

python2.7/site-packages/django/template/loader.py:97: RemovedInDjango110Warning: render() must be called with a dict, not a RequestContext.
  return template.render(context, request)

empty PDF renders due to deprecated (current) Django changes

Problem with Django 1.11 "context must be a dict rather than RequestContext"

the problem is with the context in rendering file in line 138

content = loader.render_to_string(template, context)

this gives me a error "context must be a dict rather than RequestContext" I solve this with this line of code but I think it's not the best way, check this please

content = loader.render_to_string(template, context.dicts[1])

How to display page numbers in the footer

Anyone here can tell me how to add the page number to the footer? I searched around and followed this post but I didn't get it works.

In base template file I added this block:

<div id="footerContent">
    {%block page_foot%}
        <pdf:pagenumber />
    {%endblock%}
</div>

And some styles:

@page {
     size: {{ pagesize }};
     margin: 1cm;
     @frame footer {
         -pdf-frame-content: footerContent;
         bottom: 0cm;
         margin-left: 18cm;
         margin-right: 0cm;
         height: 1cm;
    }
}

Unfortunately, it doesn't work. So could yoy please tell me what I did wrongly or am I missing something?

Inconsistencies in output

Rendering the demo template sometimes shows the correct output. Other times line heights, font size, colour etc. can go weird.

Here's my pip freeze output

Django==1.7b3
Pillow==2.4.0
PyPDF2==1.21
django-easy-pdf==0.1.0
django-extensions==1.3.6
django-shell-plus==1.1.5
gnureadline==6.3.3
html5lib==0.999
httplib2==0.9
ipython==2.0.0
pyPdf==1.13
reportlab==2.7
six==1.6.1
wsgiref==0.1.2
xhtml2pdf==0.0.5

Any ideas what could be causing the mess up?

ImportError: cannot import name inputstream

Unable to use it getting the following error:


 File "C:\Python27\lib\site-packages\xhtml2pdf\parser.py", line 17, in <module>
    from html5lib import treebuilders, inputstream
ImportError: cannot import name inputstream

This is the same error I was getting when using xhtml2pdf.

int() argument must be a string or a number, not 'tuple'

my views

from easy_pdf.views import PDFTemplateView

class HelloPDFView(PDFTemplateView):
template_name = "email-template.html"

def get_context_data(self, **kwargs):
    return super(HelloPDFView, self).get_context_data(
        pagesize="A4",
        title="Hi there!",
        **kwargs
    )

my urls

url(r"^hello$", HelloPDFView.as_view()),

http://127.0.0.1:8000/hello

TypeError at /hello
int() argument must be a string or a number, not 'tuple'

It's because of my hello.html?

string argument expected, got 'bytes'

Hey there,
I used that following code but i got "string argument expected, got 'bytes'".

from easy_pdf.views import PDFTemplateView

class ShowPDF(PDFTemplateView):
    template_name = "pdf.html"

get_context_data() missing 1 required positional argument: 'request'

Please how do I fix this

`class GeneratePdf(PDFTemplateView):
template_name = 'pdf/cv1.html'
download_filename = 'cv.pdf'

def get_context_data(self, request, **kwargs):
    profile = get_object_or_404(Profile, id=self.request.user.id)
    skill = get_object_or_404(Skill, id=self.request.user.id)
    education = Education.objects.all()
    experience = Experience.objects.all()
    return super(GeneratePdf, self).get_context_data(pagesize='A4',
                                                     profile=profile,
                                                     skill=skill,
                                                     education=education,
                                                     experience=experience)`

Does not support Sekizai tags

The current version does not support templates with Sekizai tags. Would the maintainer accept a PR that wraps the Context with SekizaiContext if Sekizai is an installed app? Otherwise, if Sekizai is not install -- it would continue behaving exactly as it does now and therefore is would be backwards compatible.

Please let me know as I have it supported in my cobbled code (not in django-easy-pdf) that can be worked into a PR. Just don't want to waste time.

Sekizai is very common and supported in our projects like Django-Compressor and django-cms.

Add docs to use this with Django Vanilla Views

Hi, i am using the Django vanilla views extension and i make this to work with just using:

from vanilla import model_views as views
from easy_pdf.views import PDFTemplateResponseMixin

class ModelDetailView(PDFTemplateResponseMixin, views.DetailView):
    template_name = 'model/detail.html'

Support loading of external resources

As documented, this library does only support loading of local resources in fetch_resources. I would like it to support loading of resources from an external URL.

My use-case is loading user generated media files from a CDN.

Can't create an CSS circle

Trying to create a circle with CSS but is always transformed into a rectangle

.circle {
	border-radius: 50%;
	width: 200px;
	height: 200px; 
}

What Im doing wrong?

Other question, can I use Font Awesome ?

Multiple pages not displayed.

Hi everyone, I'm trying to display content on multiple pages, but, when the content is very long, this content is hiding, only the first page is displayed ( without the content ), I can't display the content on multiple pages.

If the content is short then this is displayed without problems.

what is wrong ?

This is my code

Thanks!

Borders and spacing not working properly

Seems that no matter what I try, I can't get borders and spacing to work properly. I tried running demo.py and it produces a PDF but none of the tables have any borders whatsoever and everything is scrunched up together. It does not match the Live demo.

I'm running Django 1.7, reportlab 2.7, xhtml2pdf (latest from Chris Glass)

I also tried some older versions of xhtml2pdf but those produce a bunch of exceptions.

Can you tell me exactly what versions of everything you are running for the demo, including what version of django-easy-pdf it is using?

Source distribution missing on PyPI

Hey!

It seems that the source distribution for the latest stable version (0.1.1) is missing on PyPI, would you mind uploading it?

This command should do the trick:
python setup.py sdist upload

Thank you for your work on the package!

List style type not displaying

I'm experiencing a problem where the list style type of a list item is not rendered if there is a block element inside the list item.

For example, the following list will render fine:

<ul>
    <li>an item</li>
</ul>

But this list will render without a bullet point (or whatever the list-style-type was defined as):

<ul>
    <li><p>an item</p></li>
</ul>

If the block element is not the first thing in the list, it works fine. This example renders as expected:

<ul>
    <li>
        an item
        <p>a paragraph</p>
    </li>
</ul>

But, oddly, as soon as a non-block level element is added, it breaks again. The following list will have no bullet:

<ul>
    <li>
        an <em>item</em>
        <p>a paragraph</p>
    </li>
</ul>

I've experienced this with both xhtml2pdf installed from pypi and the current git master.

cyrillic symbols render as black squares

hello!

trying to use this awesome app.

it works fine with English words in template, but when rendering a template into PDF with Russian symbols they are rendered as black squares

any thoughts on this?

my template:

{% extends "easy_pdf/base.html" %}

{% block extra_style %}
{% endblock %}

{% block content %}

<section id="manager" class="margint40">

    <div class="container">

        <div class="row margint10">
            <div class="content col-lg-12 clearfix">
                <h1>Заказ #{{ order.pk }} от {{ order.created }}</h1>
                ololol
            </div>
        </div>

    </div>

</section>

{% endblock %}

and below is the rendered PDF

client

No style in the pdf. Not really an issue, more a call for help

Hi,
I am using this package in my django app but I have the following issue. When I try to reproduce the demo example within my app, I get a pdf but all the styles are missing. And I really can't figure out why.
Basically I kept the same template, put it in my folder templates where it is found. Created a view with the DemoPDFView with the relevant entry in the urls.py file.
Everything is found but there is no style to the pdf. It looks like what you see in the attachment.
The only change I did to the template was to remove the logo image because it wasn't found. Which is bizarre because I copied the relevant file and folder to my static but still wouldn't be found. Might be a clue to what is wrong.

Any idea in which direction I could be looking for the answer would be greatly appreciated.

Thanks,

document.pdf

how to show the utf-8

class HelloPDFView(PDFTemplateView):

def get_context_data(self, **kwargs):
    vul_info = vul_content.objects.filter(id=112)

    return super(HelloPDFView,self).get_context_data(
        pagesize="A4",
        title="Hi-there!",
        vul_info = vul_info,
        encoding =u"utf-8",
        **kwargs
    )
template_name = "vul_pdf.html"

lm

i use the encoding=u"utf-8"

How i can send pdf by email?

Hi, i need to create a pdf file and attach to email.
I tried do this by using html_to_pdf(), but i can't generate te file?

Thanks

Not running on Windows

I just tried to get easy_pdf to run.
With the smallest example it just happens nothing...

I tried a combination on Win7 (my devmachine), Python 2.7 in a virtualenv, Django 1.6.8 and reportlab 2.7.

Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.