Home > Software engineering >  How do I store a contentfile into ImageField in Django
How do I store a contentfile into ImageField in Django

Time:10-14

I am trying to convert an image uploaded by user into a PDF , and then store it into an ImageField in a mysql database ,using a form, but am facing an error when trying to store the PDF into the database

My views.py is:

from django.core.files.storage import FileSystemStorage
from PIL import Image
import io
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.files.base import ContentFile

def formsubmit(request):                        #submits the form
    docs = request.FILES.getlist('photos')
    print(docs)
    section = request.POST['section']
    for x in docs:
        fs = FileSystemStorage()
        print(type(x.size))
        img = Image.open(io.BytesIO(x.read()))
        imgc = img.convert('RGB')
        pdfdata = io.BytesIO()
        imgc.save(pdfdata,format='PDF')
        thumb_file = ContentFile(pdfdata.getvalue())
        filename = fs.save('photo.pdf', thumb_file)
        linkobj = Link(link = filename.file, person = Section.objects.get(section_name = section), date = str(datetime.date.today()), time = datetime.datetime.now().strftime('%H:%M:%S'))
        linkobj.save()
        count  = 1
        size  = x.size  
    return redirect('index')

My models.py:

    class Link(models.Model):
    id      = models.BigAutoField(primary_key=True)
    person  = models.ForeignKey(Section, on_delete=models.CASCADE)
    link    = models.ImageField(upload_to= 'images', default = None)
    date    = models.CharField(max_length=80, default = None)
    time    = models.CharField(max_length=80,default = None)

Error I am getting is:

AttributeError: 'str' object has no attribute 'file'

Other methods I have tried:

1) linkobj = Link(link = thumb_file, person = Section.objects.get(section_name = section), date = str(datetime.date.today()), time = datetime.datetime.now().strftime('%H:%M:%S'))

RESULT OF ABOVE METHOD: 1)The thumb_file doesnt throw an error, rather it stores nothing in the database

Points I have noticed:

1)The file is being stored properly into the media folder, ie: I can see the pdf getting stored in the media folder

How do I solve this? Thank you

CodePudding user response:

Ok so I found an answer, to be fair I wont accept my own answer as it doesn't provide an exact answer to the question I asked, rather its a different method, so if anyone does know , please do share so that the community can benefit:

My Solution: Instead of using ContentFile, I used InMemoryUploadedFile, to store the converted pdf and then moved it into the database( in an ImageField)

I am going to be honest, I am not completely sure about why ContentFile was not working, but when going through the documentation I found out that :

The ContentFile class inherits from File, but unlike File it operates on string content (bytes also supported), rather than an actual file.

Any detailed explanation is welcome

My new views.py

from django.core.files.storage import FileSystemStorage
from PIL import Image
import io
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.files.base import ContentFile
import sys

def formsubmit(request):                        #submits the form
    docs = request.FILES.getlist('photos')
    print(docs)
    section = request.POST['section']
    for x in docs:
        fs = FileSystemStorage()
        print(type(x.size))
        img = Image.open(io.BytesIO(x.read()))
        imgc = img.convert('RGB')
        pdfdata = io.BytesIO()
        imgc.save(pdfdata,format='PDF')
        thumb_file = InMemoryUploadedFile(pdfdata, None, 'photo.pdf', 'pdf',sys.getsizeof(pdfdata), None)
        linkobj = Link(link = thumb_file, person = Section.objects.get(section_name = section), date = str(datetime.date.today()), time = datetime.datetime.now().strftime('%H:%M:%S'))
        linkobj.save()
        count  = 1
        size  = x.size  
    return redirect('index')

If you have a question, you can leave it in the comments and ill try to answer it, Good luck!!!

CodePudding user response:

You don't (basically ever) need to initialize a Storage by yourself. This holds especially true since the storage for the field might not be a FileSystemStorage at all, but could e.g. be backed by S3.

Something like

import datetime
import io

from PIL import Image
from django.core.files.base import ContentFile


def convert_image_to_pdf_data(image):
    img = Image.open(io.BytesIO(image.read()))
    imgc = img.convert("RGB")
    pdfdata = io.BytesIO()
    imgc.save(pdfdata, format="PDF")
    return pdfdata.getvalue()


def formsubmit(request):  # submits the form
    photos = request.FILES.getlist("photos")  # list of UploadedFiles
    section = request.POST["section"]
    person = Section.objects.get(section_name=section)
    date = str(datetime.date.today())
    time = datetime.datetime.now().time("%H:%M:%S")
    count = 0
    size = 0
    for image in photos:
        pdfdata = convert_image_to_pdf_data(image)
        thumb_file = ContentFile(pdfdata, name="photo.pdf")
        Link.objects.create(
            link=thumb_file,
            person=person,
            date=date,
            time=time,
        )
        count  = 1
        size  = image.size
    return redirect("index")

should be enough here, i.e. using a ContentFile for the converted PDF content; the field should deal with saving it into the storage.

(As an aside, why are date and time stored separately as strings? Your database surely has a datetime type...)

  • Related