Inizia gratis

· 8 min di lettura

Generare PDF dinamici in Python / Django con JSON

Separa il layout dalla logica Django: invia il JSON dell’ordine a QuartzAPI e restituisci il PDF — senza ReportLab né dipendenze C di WeasyPrint.

In ambienti Python, generare PDF con strumenti come ReportLab significa scrivere codice procedurale per posizionamento, font e interruzioni di riga. Alternative come WeasyPrint richiedono librerie C di sistema (Cairo, Pango) che complicano Docker e il setup dei server.

Con QuartzAPI gli sviluppatori Python separano del tutto il layout dalla logica di business: Django prepara un dizionario JSON; il Visual Builder gestisce il template PDF.

Prerequisiti

  • Python 3.8+
  • Libreria requests (pip install requests)
  • Django 3.2+ / 4.x / 5.x
  • Account QuartzAPI, API key e codice template (es. ORDER_SUMMARY)

Fase 1: utility wrapper API

Crea un modulo (pdf_generator.py) nella tua app Django. Chiama generate-document, poi scarica i byte del PDF (la prima risposta è JSON con documentId / downloadUrl).

# utils/pdf_generator.py
import requests
from django.conf import settings

QUARTZ_GENERATE_URL = (
    "https://backend.quartzapi.com/index.php?r=api/v1-jobs/generate-document"
)
QUARTZ_DOWNLOAD_URL = (
    "https://backend.quartzapi.com/index.php?r=api/v1-documents/download"
)


class PDFGenerationError(Exception):
    """Eccezione custom per errori di generazione PDF."""
    pass


def render_pdf_from_template(template_code: str, data: dict) -> bytes:
    """
    Invia i dati a QuartzAPI e restituisce i byte PDF grezzi.
    """
    headers = {
        "Authorization": f"Bearer {settings.QUARTZ_API_KEY}",
        "Content-Type": "application/json",
    }

    payload = {
        "templateCode": template_code,
        "outputFormat": "pdf",
        "data": data,
    }

    try:
        generate = requests.post(
            QUARTZ_GENERATE_URL,
            json=payload,
            headers=headers,
            timeout=30,
        )
        generate.raise_for_status()
        body = generate.json()
        result = body.get("result") or {}
        document_id = result.get("documentId")
        download_url = result.get("downloadUrl") or (
            f"{QUARTZ_DOWNLOAD_URL}&uid={document_id}"
        )

        pdf = requests.get(
            download_url,
            headers={"Authorization": f"Bearer {settings.QUARTZ_API_KEY}"},
            timeout=30,
        )
        pdf.raise_for_status()
        return pdf.content
    except requests.exceptions.RequestException as e:
        raise PDFGenerationError(f"Failed to generate PDF: {str(e)}") from e

Aggiungi la API key in settings.py (in produzione preferisci variabili d’ambiente):

# settings.py
import os

QUARTZ_API_KEY = os.environ.get("QUARTZ_API_KEY", "")

Fase 2: view Django

Una view che carica i model, forma il JSON (in genere sotto master / master.items) e restituisce un HttpResponse con application/pdf.

# views.py
from django.http import HttpResponse
from django.views import View
from .utils.pdf_generator import render_pdf_from_template, PDFGenerationError


class ExportOrderPDFView(View):
    def get(self, request, order_id):
        # 1. Prepara il JSON (in produzione: Order.objects.get(pk=order_id))
        order_payload = {
            "master": {
                "order_id": f"ORD-{order_id}",
                "status": "PAID",
                "currency": "EUR",
                "shipping_address": "123 Tech Street, Milan, Italy",
                "total_amount": 199.00,
                "items": [
                    {
                        "sku": "SDK-01",
                        "name": "REST API License",
                        "qty": 1,
                        "price": 99.00,
                    },
                    {
                        "sku": "SUP-02",
                        "name": "Priority Support Ticket",
                        "qty": 2,
                        "price": 50.00,
                    },
                ],
            }
        }

        # 2. Genera i byte PDF via API
        try:
            pdf_bytes = render_pdf_from_template("ORDER_SUMMARY", order_payload)
        except PDFGenerationError as err:
            return HttpResponse(str(err), status=500)

        # 3. Stream del PDF al browser
        response = HttpResponse(pdf_bytes, content_type="application/pdf")
        response["Content-Disposition"] = (
            f'attachment; filename="order_{order_id}.pdf"'
        )
        return response

Allinea i nomi campo ai binding del template. Approfondimento sul pattern JSON→PDF: generare fatture PDF da JSON.

Fase 3: routing URL

Collega la view in urls.py dell’app:

# urls.py
from django.urls import path
from .views import ExportOrderPDFView

urlpatterns = [
    path(
        "orders/<int:order_id>/pdf/",
        ExportOrderPDFView.as_view(),
        name="export_order_pdf",
    ),
]

Riepilogo

Con questo pattern l’app Django resta libera da dipendenze C di sistema come Cairo o Pango, i container restano leggeri e i template PDF si aggiornano visivamente senza riavviare i worker WSGI/ASGI.

Approccio Codice di layout Ops / Docker
ReportLab X/Y procedurale in Python Pure Python, ma layout nel repo
WeasyPrint HTML/CSS + librerie di sistema Cairo, Pango, font nell’immagine
QuartzAPI Visual Builder cloud Solo requests

Conclusioni

Tratta la generazione PDF come integrazione HTTP, non come sottosistema grafico dentro Django. Modelli e serializer restano in Python; tipografia e salti pagina restano su QuartzAPI.

Pronto a togliere ReportLab / WeasyPrint? Registrati alla Beta QuartzAPI, crea un template ordine e collega render_pdf_from_template alla view di export.

👉 Inizia gratis con la Beta QuartzAPI

Snippet pronti

  • Generate: POST https://backend.quartzapi.com/index.php?r=api/v1-jobs/generate-document con templateCode + data.
  • Auth: Authorization: Bearer {settings.QUARTZ_API_KEY}.
  • Download: result.downloadUrl oppure GET …/v1-documents/download&uid=….
  • Docs: Documentazione Web API.