Blog (5)
Komentarze (0)
Recenzje (0)
@skwReportlab – wygenerowanie i pobranie pdf-a we Flasku

Reportlab – wygenerowanie i pobranie pdf‑a we Flasku

20.07.2021 08:04, aktualizacja: 20.07.2021 08:20

Rozwiązany problem: jak wygenerować pdf z danymi zamówienia i kodem paskowym rezerwacji bez zapisu pliku na dysku, który może być następnie pobrany przez użytkownika serwisu we Flasku.

from io import BytesIO
from reportlab.pdfgen.canvas import Canvas
from reportlab.lib.pagesizes import A4

buffer = BytesIO()
canvas = Canvas(buffer, pagesize=A4)

Aby użyć niestandardowych znaków np. polskich liter z ogonkami należy zarejestrować odpowiednie czcionki, które obsługują wymagane znaki. W przykładowym pliku pdf użyłem czcionki Vera.

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

pdfmetrics.registerFont(TTFont('Vera', 'Vera.ttf'))

Tak zarejestrowaną czcionkę można już użyć:

canvas.setFont("Vera", size=10)

Obrazy wygenerowane na podstawie danych z aplikacji (w tym przypadku kod kreskowy rezerwacji) umieszczam w tworzonym dokumencie za pomocą metody drawImage(), która jako pierwszy argument pobiera obiekt ImageReader tzn.

im = ImageReader(image)
canvas.drawImage(im, x=0, y=-5*cm, width=150, height=100)

Listę zawierającą łańcuchy tekstowe można dodać do dokumentu wykorzystując obiekt tekstowy tzn.

txt_obj = canvas.beginText(14, -6.5 * cm)
txt_lst = ["line of text 1", "line of text 2", "line of text 3"]
for line in txt_lst:
        txt_obj.textOut(line)
        txt_obj.moveCursor(0, 16)
canvas.drawText(txt_obj)

Tabelę do dokumentu można dodać za pomocą obiektu klasy Table tzn. osobno definiuję listę zawierającą dane poszczególnych wierszy tabeli (zmienna table_data). Osobno również definiuję style obowiązujące w całej lub w części tabeli.

t = Table(table_data, colWidths=[60, 230, 70, 60, 50], rowHeights=30)
style = [('BACKGROUND',(0,0),(-1,-2),colors.lightblue),
            ('ALIGN',(0,-1),(-1,-1),'CENTER'),
            ('BOX', (0,0), (-1,-1), 0.25, colors.black),
            ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
            ('FONTSIZE', (0,0), (-1,-1), 10),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE')]
t.setStyle(tblstyle=style)
t.wrapOn(canvas, 10, 10)
t.drawOn(canvas=canvas, x=20, y=-22*cm)

Następnie zapisuję tak utworzony obiekt Canvas i zwracam powstały bufor do kontrolera. W celu przesłania pliku pdf na podstawie danych z bufora wykorzystuję funkcję send_file() Flaska:

from flask.helpers import send_file

@bp.route('/get-pdf/<int:id>', methods=['GET'])
@login_required
def get_pdf(id):
    contract = Contract.query.get(id)
    contractor = User.query.get(contract.contractor_id)
    booking = Booking.query.filter_by(contract_id=contract.id).first()
    pdf = create_pdf(booking_no=booking.id,
                        contractor=contractor.username,
                        contractor_no=contractor.id,
                        truck_plate=booking.truck_reg_number,
                        warehouse=contract.warehouse,
                        date=contract.date_of_delivery,
                        time=booking.booking_time,
                        pallets_pos=contract.pallets_position,
                        pallets=contract.pallets_actual)
    pdf.seek(0)
    return send_file(pdf, as_attachment=True, 
                        mimetype='application/pdf',
                        attachment_filename='booking.pdf', 
                        cache_timeout=0)
przykładowy plik zamówienia.
przykładowy plik zamówienia.© źródło:&nbsp;https://www.slawomirkwiatkowski.pl
Wybrane dla Ciebie
Komentarze (1)