【问题标题】:Saving PDFs to disk as they are generated with django-wkhtmltopdf将使用 django-wkhtmltopdf 生成的 PDF 保存到磁盘
【发布时间】:2020-08-20 20:05:46
【问题描述】:

我想要实现的是:

  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,这很好。

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

Save pdf from django-wkhtmltopdf to server (instead of returning as a response)

这是我目前在 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'),
]

# 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)
# settings.py
...
DOWNLOAD_ROOT = '/mnt/files/client-downloads/'
MEDIA_ROOT = '/mnt/files/client-submissions/'
PDF_DIR = '/mnt/files/pdf-sections/'
...

我应该注意到其他 DOWNLOAD_ROOTMEDIA_ROOT 在应用程序使用它们的地方工作正常。我什至尝试过使用settings.MEDIA_ROOT,因为我知道它可以工作,但那里仍然没有保存任何内容。但正如你所见,我是从超级基础开始的,还没有添加查询、循环等。

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

with open("file.pdf", "wb") as f:
    f.write(response.rendered_content)

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

也许我需要使用不同的库来满足我的需要,因为 django-wkhtmltopdf 似乎做了很多我不希望我不知道可以覆盖的开箱即用的事情。

【问题讨论】:

    标签: python django pdf wkhtmltopdf django-wkhtmltopdf


    【解决方案1】:

    好的,我光滑的大脑一夜之间波澜不惊,今天早上想通了:

    # 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!')
    

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

    【讨论】:

    • 我发现自己不得不做一些与此非常相似的事情。如果我现在必须将新创建的 pdf 文件与模型中的 FileField 相关联,是否像在 with open... 块内调用 my_instance.pdf_file_field = f 然后 my_instance.save() 一样简单?还是您认为我必须更改您发布的代码的其他部分?
    猜你喜欢
    • 2020-01-13
    • 2014-07-27
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-07-03
    • 2017-11-20
    • 2018-09-14
    相关资源
    最近更新 更多