PDF generation with gotenberg

hi! /ᐠ. ̫ .ᐟ\ฅ

I’m currently trying to generate pdfs in my django app. For this I’ve settled on using gotenberg with gotenberg-client.
I’ve tested generating pdfs outside django with a simple script and it works well.

The problem I’m having is that I’m not too sure what to do on the django side. I want a view that returns a PDF, but when I tried following this example on the documentation the result is a blank pdf.

gotenberg-client has a method to write the response to a file, which was generated correctly, so I am 99% sure it is something I’m doing wrong on the django side.

Here is the code I’m using to generate pdfs:

def render_pdf_from_template(
    template: str,
    context: dict[str, object] | None = None,
    request: HttpRequest | None = None,
    using: str | None = None,
    resources: list[Path] | None = None,
) -> bytes | bytearray:
    """Given a django template returns a pdf made with gotenberg

    Args:
        template (list[str] | str): string or strings to a django template
        context (dict[str, object] | None, optional): context that goes inside the template. Defaults to None.
        request (HttpRequest | None, optional): optional request for the template. Defaults to None.
        using (str | None, optional): template engine to use. Defaults to None.
        resources (list[Path] | None, optional): additional paths to resources to render the pdf (images, stylesheets, etc). Defaults to None.

    Raises:
        ValueError: Raised the if the URL is not found
        Exception: Raised if it's not possible to connect to the URL

    Returns:
        bytes | bytearray: rendered pdf from gotenberg
    """

    rendered_html = render_to_string(
        template_name=template, context=context, request=request, using=using
    )

    url = getattr(settings, "GOTENBERG_URL", None)

    if not url:
        raise ValueError("GOTENBERG_URL missing in settings")

    try:
        with GotenbergClient(url) as client:
            with client.chromium.html_to_pdf() as route:
                response = route.string_index(rendered_html)

                if resources:
                    response = response.resources(resources)

                response = response.run()

                # see if pdf is generated correctly
                response.to_file(Path("my-index.pdf"))

                return response.content
    except ConnectError:
        raise Exception(f"Error connecting to {url}")

And here is the mixin I’m adding to my views:

class PDFMixin(TemplateResponseMixin):
    resources: list[Path] | None = None
    filename: str
    content_type = "application/pdf"

    def render_to_response(self, context, **response_kwargs):
        response_kwargs.setdefault("content_type", self.content_type)

        pdf = render_pdf_from_template(
            template=self.get_template_names(),
            context=context,
            request=self.request,
            using=self.template_engine,
            resources=self.resources,
        )

        return FileResponse(
            pdf, as_attachment=True, filename=self.filename, **response_kwargs
        )
class PDFMixin(TemplateResponseMixin):
    resources: list[Path] | None = None
    filename: str
    content_type = "application/pdf"

    def render_to_response(self, context, **response_kwargs):
        response_kwargs.setdefault("content_type", self.content_type)

        pdf_bytes = render_pdf_from_template(
            template=self.get_template_names(),
            context=context,
            request=self.request,
            using=self.template_engine,
            resources=self.resources,
        )

        pdf_io = BytesIO(pdf_bytes)

        return FileResponse(pdf_io, filename=self.filename, **response_kwargs)