-->

How to link stylesheet files to pdfkit in Flask ap

2019-04-15 00:29发布

问题:

I am trying to create pdf from html page using pdfkit inside Flask application, but I have troubles to load the static files (stylesheets) when using pdfkit.

I've tried to come up with minimal example. I've got this file structure

App
 |_ static
 |  |- style.css
 |_ templates
 |  |- base.html
 |_ pdfs
 |  |- file.pdf
 |_ application.py

Inside application.py:

import flask
import pdfkit
app = flask.Flask(__name__)

@app.route('/')
def index():

    page = flask.render_template('base.html')
    pdfkit.from_string(page, 'pdfs/file.pdf')
    return page

@app.route('/download', methods=['POST'])
def download():

    if flask.request.method == 'POST':
        flask.send_from_directory(
        directory='pdfs', filename='file.pdf', as_attachment=True)
    else:
        flask.redirect(flaks.url_for('index'))

if __name__ == '__main__':

    app.run()

Stylesheet just adds red background to the td elements:

td {
    background-color: red;
}

And finally the base.html:

<!DOCTYPE html>
<html>
<head>
  <title>Test App</title>
  <link href={{ url_for('static', filename='style.css') }} rel='stylesheet'>
</head>
<body>
  <div id='to_pdf'>
    <table>
      <tr>
        <th>Firstname</th>
      </tr>
      <tr>
        <td>Jill</td>
      </tr>
      <tr>
        <td>Eve</td>
      </tr>
    </table>
    <form action='/download' method='POST'>
      <button type="submit" value="Print" />PRINT</form>
    </form>
  </div>
</body>
</html>

Sorry for the loads of code, but it is actually pretty basic. All I want is to have button, which once clicked downloads a pdf file (this pdf is html file converted to pdf.

It sort of works, but the console output is the following:

Loading pages (1/6)
Warning: Failed to load file:///static/style.css (ignore)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done

The problem

pdfkit, which basically invokes wkhtmltopdf cannot find the stylesheet files inside static folder. The application, where I have this problem is more robust, uses boostrap etc. and having the pdf output badly formatted is very undesirable..

回答1:

Assuming your app has config.py file you can add this config value.

ABS_PATH_STATIC_FOLDER = "var/www/.." #here is an absolute path to static dir

Then specify css file by:

css = os.path.join(app.config['ABS_PATH_STATIC_FOLDER'], 'pdfstyle.css')

This will work if the css file is placed in static folder or any other folder

Then pass on css to pdfkit fromstring function

pdfkit.from_string(page, 'pdfs/file.pdf', css=css)


回答2:

Single CSS file

css = 'example.css'
pdfkit.from_file('file.html', css=css)

Multiple CSS files

css = ['example.css', 'example2.css']
pdfkit.from_file('file.html', css=css)

In your case try this:

css = "static/style.css"
page = flask.render_template('base.html')
pdfkit.from_string(page, 'pdfs/file.pdf', css=css)
return page


回答3:

Your code results in a link that wkhtmltopdf tries to open as a regular file:

{{ url_for('static', filename='style.css') }}

becomes

/static/style.css

which wkhtmltopdf will look for at

file://static/style.css

Instead, add the _external=True flag to point it towards the file on the server:

{{ url_for('static', filename='style.css', _external=True) }}

results in (something like)

http://localhost:5000/static/style.css