如何将io.BytesIO pdfrw中的PDF保存到Django的FileField?

6
我想做的基本上是:
  1. 从URL获取PDF
  2. 通过pdfrw修改它
  3. 将其作为BytesIO对象存储在内存中
  4. 通过Model.objects.create(form=pdf_file, name="Some name")上传到Django FileField
我的问题是,当create()方法运行时,它保存了所有字段,除了form
import io
import tempfile
from contextlib import contextmanager

import requests
import pdfrw


@contextmanager
def as_file(url):
    with tempfile.NamedTemporaryFile(suffix='.pdf') as tfile:
        tfile.write(requests.get(url).content)
        tfile.flush()
        yield tfile.name


def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict):
    template_pdf = pdfrw.PdfReader(input_pdf_path)

    ## PDF is modified here

    buf = io.BytesIO()
    print(buf.getbuffer().nbytes). # Prints "0"!
    pdfrw.PdfWriter().write(buf, template_pdf)
    buf.seek(0)
    return buf

views.py

from django.core.files import File

class FormView(View):
    def get(self, request, *args, **kwargs):
        form_url = 'http://some-pdf-url.com'

        with as_file(form_url) as temp_form_path:
            submitted_form = write_fillable_pdf(temp_form_path, temp_form_path, {"name": "John Doe"})
            print(submitted_form.getbuffer().nbytes).  # Prints "994782"!
            FilledPDF.objects.create(form=File(submitted_form), name="Test PDF") 
        return render(request, 'index.html', {})

正如您所看到的,print() 在填充 BytesIO 时会给出两个不同的值,这让我认为增加的大小意味着实际上有数据。是否有原因导致它没有正确保存到我的 Django 模型实例中?另外,如果有人知道更有效的方法,请告诉我!

2个回答

11
您可以在代码中使用ContentFile类。我已经相应地修改了您的视图,以便将文件保存在filefield中。
from django.core.files.base import ContentFile

class FormView(View):
    def get(self, request, *args, **kwargs):
        form_url = 'http://some-pdf-url.com'

        with as_file(form_url) as temp_form_path:
            submitted_form = write_fillable_pdf(temp_form_path, temp_form_path, {"name": "John Doe"})
            pdf_content = ContentFile(submitted_form.getvalue(), 'sample.pdf')
            FilledPDF.objects.create(form=pdf_content, name="Test PDF") 
        return render(request, 'index.html', {})

您还可以使用save方法,使用ContentFile类存储文件。

from django.core.files.base import ContentFile

    class FormView(View):
        def get(self, request, *args, **kwargs):
            form_url = 'http://some-pdf-url.com'

            with as_file(form_url) as temp_form_path:
                submitted_form = write_fillable_pdf(temp_form_path, temp_form_path, {"name": "John Doe"})
                pdf_content = ContentFile(submitted_form.getvalue())
                filled_pdf = FilledPDF()
                filled_pdf.name = "Test PDF"
                filled_pdf.form.save("sample.pdf", pdf_content, save=False)
                filled_pdf.save()
            return render(request, 'index.html', {})

很遗憾,这不起作用 :( 我的模型实例已保存,但“表单”字段未显示上传的文件。 - Hybrid
@Hybrid,忘记在“ContentFile”实例中添加文件名。更新它并添加另一种存储文件的方式。这将起作用 :) - PyMaster
谢谢!看起来文件没有正常保存,因为我忘记了文件名。 - Hybrid

3

这里是有关如何将文件保存至对象的文档

from django.core.files import File

filled_pdf = FilledPDF()
filled_pdf.form.save('test_pdf.pdf', File(submitted_form.getvalue()), save=True)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接