我正在编写一个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
)
您可以使用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)
你可以使用标准的Python模块tempfile
(import 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美元=)