使用 django-wkhtmltopdf 生成时将 PDF 保存到磁盘
Saving PDFs to disk as they are generated with django-wkhtmltopdf
我要实现的是:
- 用户将查询参数从 React FE 微服务发送到 Django BE 微服务。
- URI 类似于
/api/reports?startingPage=12&dataView=Region
- 这些 PDF 太大而无法在 FE 中生成,所以在服务器端生成
- 请求进入
view.py
,从数据库中查询与 dataView=Region
相关的数据,遍历每一行并为每个项目生成一个 PDF 报告
- 每个
dataView=Region
可以包含几百个项目,每个项目都是自己的报告,可以是一页或几页长
- 生成报告时,应将它们保存到服务器永久卷声明中,并且不要发送回 FE 直到它们全部 运行.
- 等他们都运行,我打算用
pypdf2
把所有的PDF合并成一个大文件。
- 此时,文件被发送回 FE 进行下载。
目前我只在处理 1. 和 3.,我无法:
- 获取要保存到存储的文件
- 防止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_ROOT
和 MEDIA_ROOT
在应用程序使用它们的地方工作正常。我什至尝试过使用 settings.MEDIA_ROOT
因为我知道它有效,但仍然没有保存任何东西。但如您所见,我从超级基础开始,没有添加查询、循环等。
我的 save_pdf()
与我链接到的 SO 问题不同,因为那是我在我的应用程序的其他部分中使用的,并且它在那里保存文件很好。我确实尝试了他们在 SO 问题中提供的内容,但结果相同,但没有保存。即:
with open("file.pdf", "wb") as f:
f.write(response.rendered_content)
那么我需要做什么才能将这些 PDF 保存到磁盘?
也许我需要使用不同的库来满足我的需要,因为 django-wkhtmltopdf
似乎开箱即用了很多我不想要的东西,我不清楚我是否可以覆盖。
好的,我光滑的大脑一夜之间起了一些涟漪,今天早上想通了:
# 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。显然是一个我可以扩展的最小功能示例,但至少解决了这两个问题。
我要实现的是:
- 用户将查询参数从 React FE 微服务发送到 Django BE 微服务。
- URI 类似于
/api/reports?startingPage=12&dataView=Region
- 这些 PDF 太大而无法在 FE 中生成,所以在服务器端生成
- URI 类似于
- 请求进入
view.py
,从数据库中查询与dataView=Region
相关的数据,遍历每一行并为每个项目生成一个 PDF 报告- 每个
dataView=Region
可以包含几百个项目,每个项目都是自己的报告,可以是一页或几页长
- 每个
- 生成报告时,应将它们保存到服务器永久卷声明中,并且不要发送回 FE 直到它们全部 运行.
- 等他们都运行,我打算用
pypdf2
把所有的PDF合并成一个大文件。 - 此时,文件被发送回 FE 进行下载。
目前我只在处理 1. 和 3.,我无法:
- 获取要保存到存储的文件
- 防止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_ROOT
和 MEDIA_ROOT
在应用程序使用它们的地方工作正常。我什至尝试过使用 settings.MEDIA_ROOT
因为我知道它有效,但仍然没有保存任何东西。但如您所见,我从超级基础开始,没有添加查询、循环等。
我的 save_pdf()
与我链接到的 SO 问题不同,因为那是我在我的应用程序的其他部分中使用的,并且它在那里保存文件很好。我确实尝试了他们在 SO 问题中提供的内容,但结果相同,但没有保存。即:
with open("file.pdf", "wb") as f:
f.write(response.rendered_content)
那么我需要做什么才能将这些 PDF 保存到磁盘?
也许我需要使用不同的库来满足我的需要,因为 django-wkhtmltopdf
似乎开箱即用了很多我不想要的东西,我不清楚我是否可以覆盖。
好的,我光滑的大脑一夜之间起了一些涟漪,今天早上想通了:
# 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。显然是一个我可以扩展的最小功能示例,但至少解决了这两个问题。