Как обслуживать файл PDF, созданный pdfkit.from_string () с Flask send_file () - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть PDF-файл PDF, который отлично работает как вложение Sendgrid, созданный следующей функцией:

def wish_lists_pdf(user=current_user):
    pdf_heading = "Thank you!"
    pdf_subheading = "Please find the Wish Lists you signed up to sponsor listed below."

    pdf_context = {
        'heading': pdf_heading,
        'subheading': pdf_subheading,
        'user': user,
    }
    css = os.path.join(basedir, 'static/main.css')
    pdf_content = render_template(
        'partials/email_lists_pdf.html', **pdf_context)

    path_wkhtmltopdf = app.config['WKHTMLTOPDF_EXE']
    config = pdfkit.configuration(wkhtmltopdf=path_wkhtmltopdf)

    pdf_file = pdfkit.from_string(
        pdf_content, False, configuration=config, css=css)

    bytes_file = BytesIO(pdf_file)

    return bytes_file

На самом деле, sendgrid нужна эта строка вместо байтовой кодировки:

    encoded_file = base64.b64encode(pdf_attachment).decode()

Я пробовал использовать эту кодировку и кодировку b64, как предлагали разные учебники. Я не совсем понимаю цель кодирования, поэтому это может быть причиной моей ошибки. В любом случае, вот маршрут, который я хочу обслуживать в PDF-файле:

@bp.route('download_lists_pdf/<int:user_id>', methods=['GET'])
def download_lists_pdf(user_id):
    user = User.query.filter_by(id=user_id).first()
    pdf_file = wish_lists_pdf(user=user)
    return send_file(
        pdf_file,
        as_attachment=True,
        attachment_filename="Wish List Reminder Page.pdf",
        mimetype='application/pdf',
        )

Это загружает совершенно пустой PDF-файл размером 0 КБ. Может кто-нибудь помочь мне понять, как использовать send_file () таким образом, чтобы я мог обслужить этот PDF-файл из pdfkit? Опять же, в качестве вложения Sendgrid файл работает нормально.

Вот конфигурация вложения sendgrid, если это полезно ...

    context = {
        'heading': heading,
        'subheading': subheading,
        'user': user,
    }

    message = Mail(
        from_email=app.config['ADMIN_EMAIL'],
        to_emails=app.config['EMAIL_RECIPIENTS'],
        subject=email_subject,
        html_content=render_template('partials/email_lists.html', **context),
    )

    encoded_file = base64.b64encode(pdf_attachment).decode()

    attached_file = Attachment(
        FileContent(encoded_file),
        FileName('Wish List Reminder Page.pdf'),
        FileType('application/pdf'),
        Disposition('attachment')
    )
    message.attachment = attached_file

    sg = SendGridAPIClient(app.config['SENDGRID_API_KEY'])
    response = sg.send(message)

Заранее благодарю за помощь.

Редактировать: попробовал ниже, и это не сработало

    bytes_file = BytesIO(pdf_file)

    return bytes(bytes_file), 200, {
        'Content-Type': 'application/pdf',
        'Content-Disposition': 'inline; filename="Wish List reminder sheet.pdf"'}

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Я нашел решение. Он использует файл PDF, возвращенный непосредственно из pdfkit, а затем использует Flask Ответ для обслуживания файла.

Вот функция, которая возвращает файл PDF:

def wish_lists_pdf(user=current_user):
    pdf_heading = "Thank you!"
    pdf_subheading = "Please find the Wish Lists you signed up to sponsor listed below."

    pdf_context = {
        'heading': pdf_heading,
        'subheading': pdf_subheading,
        'user': user,
    }
    css = os.path.join(basedir, 'static/main.css')
    pdf_content = render_template(
        'partials/email_lists_pdf.html', **pdf_context)

    path_wkhtmltopdf = app.config['WKHTMLTOPDF_EXE']
    config = pdfkit.configuration(wkhtmltopdf=path_wkhtmltopdf)

    pdf_file = pdfkit.from_string(
        pdf_content, False, configuration=config, css=css)

    return pdf_file

А вот представление:

@bp.route('download_lists_pdf/<int:user_id>', methods=['GET'])
def download_lists_pdf(user_id):
    user = User.query.filter_by(id=user_id).first()
    pdf_file = wish_lists_pdf(user=user)

    response = Response(pdf_file)
    response.headers['Content-Disposition'] = "inline; 'Wish List reminder page'"
    response.mimetype = 'application/pdf'
    return response

Я думаю, что было бы более идеальным, если бы он открывался в новой вкладке или загружался без открытия в браузере, но пока этого достаточно.

0 голосов
/ 15 апреля 2020

Если у вас есть PDF как bytes_file,

return bytes(byte_file), 200, {
    'Content-Type': 'application/pdf',
    'Content-Disposition': 'inline; filename="nameofyourchoice.pdf"'}

должно сработать.

...