Как сохранить PDF-файл io.BytesIO pdfrw в Django FileField - PullRequest
1 голос
/ 11 февраля 2020

Я пытаюсь сделать следующее:

  1. Получить PDF с URL
  2. Изменить его с помощью pdfrw
  3. Сохранить его в памяти как объект BytesIO obj
  4. Загрузить его в Django FileField через Model.objects.create(form=pdf_file, name="Some name")

Моя проблема заключается в том, что при запуске метода create() сохраняются все поля , за исключением для form.

helpers.py

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', {})

As Вы можете видеть, что print() выдает два разных значения при заполнении BytesIO, что наводит меня на мысль, что увеличение размера означает, что в нем действительно есть данные. Есть ли причина, по которой он не сохраняется должным образом в моем экземпляре модели django? Кроме того, если кто-нибудь знает более эффективный способ сделать это, пожалуйста, дайте мне знать!

Ответы [ 2 ]

2 голосов
/ 14 февраля 2020

Вы можете использовать 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(), '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', {})
1 голос
/ 14 февраля 2020

Вот документация по как сохранить файл на объекте .

from django.core.files import File

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