将使用 django-wkhtmltopdf 生成的 PDF 保存到磁盘

soc*_*pet 2 python pdf django wkhtmltopdf django-wkhtmltopdf

我想要实现的是:

  1. 用户将查询参数从 React FE 微服务发送到 Django BE 微服务。
    • URI 是这样的/api/reports?startingPage=12&dataView=Region
    • 这些 PDF 太大,无法在 FE 中生成,因此需要在服务器端生成
  2. 请求进入从数据库查询view.py相关数据的位置dataView=Region,迭代每一行并为每个项目生成 PDF 报告
    • 每个dataView=Region项目可以包含数百个项目,每个项目都是自己的报告,可以是一页长或几页长
  3. 生成报告后,应将它们保存到服务器持久卷声明中,并且在全部运行之前不会将其发送回 FE。
  4. 当它们全部运行后,我计划将pypdf2所有 PDF 合并成一个大文件。
  5. 此时,文件被发送回 FE 进行下载。

我目前只致力于 1. 和 3.,但我无法:

  1. 获取要保存到存储的文件
  2. 防止 PDF 生成后发送回 FE 的默认行为

PDF 正在生成,所以这很好。

我正在尝试实施此处找到的建议,但没有得到预期的结果:

将 pdf 从 django-wkhtmltopdf 保存到服务器(而不是作为响应返回)

这是我目前在 Django 方面的内容:

# urls.py

from django.urls import path

from .views import GeneratePDFView

app_name = 'Reports'

urlpatterns = [
    path('/api/reports',
        GeneratePDFView.as_view(), name='generate_pdf'),
]

Run Code Online (Sandbox Code Playgroud)
# views.py

from django.conf import settings
from django.views.generic.base import TemplateView

from rest_framework.permissions import IsAuthenticated

from wkhtmltopdf.views import PDFTemplateResponse

# Create your views here.

class GeneratePDFView(TemplateView):
    permission_classes = [IsAuthenticated]
    template_name = 'test.html'
    filename = 'test.pdf'

    def generate_pdf(self, request, **kwargs):
        context = {'key': 'value'}

        # generate response
        response = PDFTemplateResponse(
            request=self.request,
            template=self.template_name,
            filename=self.filename,
            context=context,
            cmd_options={'load-error-handling': 'ignore'})

        self.save_pdf(response.rendered_content, self.filename)

    # Handle saving the document
    # This is what I'm using elsewhere where files are saved and it works there
    def save_pdf(self, file, filename):
        with open(settings.PDF_DIR + '/' + filename, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
Run Code Online (Sandbox Code Playgroud)
# settings.py
...
DOWNLOAD_ROOT = '/mnt/files/client-downloads/'
MEDIA_ROOT = '/mnt/files/client-submissions/'
PDF_DIR = '/mnt/files/pdf-sections/'
...
Run Code Online (Sandbox Code Playgroud)

我应该注意到另一个,DOWNLOAD_ROOT并且MEDIA_ROOT在应用程序使用它们的地方工作得很好。我什至尝试过使用,settings.MEDIA_ROOT因为我知道它有效,但那里仍然没有保存任何内容。但正如你所看到的,我从超级基础开始,没有添加查询、循环等。

我的save_pdf()问题与我链接到的问题不同,因为这是我在应用程序的其他部分中使用的问题,并且它在那里保存文件很好。我确实尝试了他们在 SO 问题中提供的内容,但得到了相同的结果,但没有保存。那是:

with open("file.pdf", "wb") as f:
    f.write(response.rendered_content)
Run Code Online (Sandbox Code Playgroud)

那么我需要做什么才能将这些 PDF 保存到磁盘呢?

也许我需要使用不同的库来满足我的需求,因为django-wkhtmltopdf似乎可以做一些开箱即用的事情,但我不希望我不清楚我可以覆盖这些事情。

soc*_*pet 5

好吧,我光滑的大脑一夜之间激起了一些涟漪,今天早上就弄清楚了:

# views.py

class GeneratePDFView(TemplateView):
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        template_name = 'test.html'
        filename = 'test.pdf'
        context = {'key': 'value'}

        # generate response
        response = PDFTemplateResponse(
            request=request,
            template=template_name,
            filename=filename,
            context=context,
            cmd_options={'load-error-handling': 'ignore'})

        # write the rendered content to a file
        with open(settings.PDF_DIR + '/' + filename, "wb") as f:
            f.write(response.rendered_content)

        return HttpResponse('Hello, World!')
Run Code Online (Sandbox Code Playgroud)

这将 PDF 保存到磁盘,并且 PDF 也没有响应。显然,这是一个功能最少的示例,我可以对其进行扩展,但至少解决了这两个问题。