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
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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…)
Method 2
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!!!
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0