Django / reportlab:将生成的pdf直接保存到AWS s3中的FileField

时间:2017-04-12 14:52:24

标签: python django amazon-web-services amazon-s3 reportlab

我正在编写一个Django应用程序,我需要使用reportlab生成PDF,然后将其保存到FileField。我的问题是我的媒体存储在S3中,我不知道如何将这个pdf直接保存到S3。

我在本地创建pdf,然后将其读取并保存到s3中的FileField,然后删除本地版本,但我想知道是否有更好的解决方案,我可以将文件直接保存到S3。

现在我如何生成合同:

#temporary folder name to generate contract locally
folder_name = (
     '/tmp/'
     + '/contracts/'
     + gig.identifier
     )
mkdir_p(folder_name)
address = (
     folder_name
     + '/contract_'
     + lang
     + '.pdf'
 )
doc = SimpleDocTemplate(
     address,
     pagesize=A4,
     rightMargin=72,
     leftMargin=72,
     topMargin=120,
     bottomMargin=18
 )
doc.build(Story,
          canvasmaker=LogoCanvas)
local_file = open(address)
pdf_file = File(local_file)
contract = Contract.objects.create(lang=lang, gig=gig)
contract.contract_file.save('contract_'+lang+'.pdf', pdf_file)
contract.save()
#remove temporary folder
shutil.rmtree(folder_name)
return True

并且合同模型定义如下:

class Contract(models.Model):
    gig = models.ForeignKey(Gig, related_name='contracts')
    lang = models.CharField(max_length=10, default='')
    contract_file = models.FileField(
        upload_to=get_contract_path,
        blank=True,
        null=True,
        default=None
    )

3 个答案:

答案 0 :(得分:0)

您可以使用BytesIO创建内存中的流而不是文件流。

但是,您仍然需要使reportlab使用该流而不是文件。

依赖于userguide,在 2.2关于Canvas的更多信息,Canvas构造函数有一个filename参数,可以是字符串或文件描述符。我已使用SimpleDocTemplate对其进行了测试,因此它适用于您:

import io
stream = io.BytesIO()
doc = SimpleDocTemplate(
     stream,
     pagesize=A4,
     rightMargin=72,
     leftMargin=72,
     topMargin=120,
     bottomMargin=18
 )
doc.build(Story,
          canvasmaker=LogoCanvas)
pdf_buffer = stream.getBuffer()

我不了解S3,但我确信这足以解决您的问题。例如,如果您现在想将此pdf写入文件,您可以这样做:

file = open("contract.pdf", "wb")
file.write(pdf_buffer)

答案 1 :(得分:0)

您可以使用标准的Python模块tempfileimport tempfile

tempfile.TemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None)
  

返回可用作临时存储区的类似文件的对象。使用与mkstemp()相同的规则安全地创建文件。它将在关闭后立即销毁(包括在垃圾回收对象时的隐式关闭)。在Unix下,该文件的目录条目根本没有创建,或者在创建文件后立即删除。其他平台不支持此功能。您的代码不应依赖使用此功能创建的临时文件,该文件在文件系统中是否具有可见名称。

https://docs.python.org/3/library/tempfile.html 您对tempfile对象的使用与常规文件绝对相似。

按你欠我25美元=的方式

答案 2 :(得分:0)

您可以将生成的pdf直接保存到S3。

我使用boto3库来处理s3中的存储,我认为您使用的是相同的方法。

from api.models import Entity
from django.core.files.base import ContentFile

entity = Entity.objects.create(**create_params)
pdf = render_to_pdf('invoice.html') # returns BytesIO
entity.pdf_field.save('invoice.pdf', ContentFile(pdf.getvalue()), save=True)