Search code examples
pythondjangodjango-modelsinstanceimagefield

Django. How to create a new instance of a model from views.py with an image field in the model


I am trying to create a new instance of a model that has an image field in it. I take a PDF from a form and convert it to a png file format and am now trying to save the png image to a model data base but get the error 'PngImageFile' object has no attribute '_committed'. I know you cant save an image directly to a data base but i'm wondering how can you save the image to the media folder and save the image url path to the image in the data base? Help greatly appreciated.

This is my form to take in the PDF (forms.py)

class DrawingPDFForm(forms.Form):
    drawing_name = forms.CharField(max_length=50)
    file = forms.FileField()

This is my view to convert PDF to PNG and then create new instance of model to save to database(views.py)

def upload_drawings(request):
    if request.method == "POST":
        form  = DrawingPDFForm(request.POST, request.FILES)
        drawing_name = request.POST['drawing_name']
        file = request.FILES['file']
        pdf_byt = file.read()
        pdf_content = BytesIO(pdf_byt) 
        pdf_content.seek(0)
        pdf_converted = convert_from_bytes(pdf_content.read(),    poppler_path=r"C:\Python\Python\Programs\plant_locator\poppler\poppler-23.07.0\Library\bin")
        buffer = BytesIO()
        pdf_converted[0].save(buffer, 'png')
        png_byt = buffer.getvalue()
        my_string = base64.b64encode(png_byt)
        pdf_png_byt_decode = base64.b64decode(my_string)
        png = Image.open(BytesIO(pdf_png_byt_decode))
        drawing = Drawing.objects.create(drawing_name=drawing_name, drawing=png)#error occurs here as #expected
        drawing.save()
        return HttpResponseRedirect('/upload_drawings')
    else:
        form  = DrawingPDFForm()
    return render(request, 'upload_drawings.html', {'form':form})

This is my model I am trying to create a new instance of (models.py)

from django.db import models


class Drawing(models.Model):
    drawing_name = models.CharField('Drawing Name', max_length=50)
    drawing = models.ImageField(null=True, blank=True, upload_to="images/")
    

    def __str__(self):
        return self.drawing_name

Solution

  • this is what comes to my mind

    in your "url.py" file add the following line at the end of your "urlpatterns":

    from djano.conf import settings
    from django .conf.urls.static import static
    
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

    and now you should modify your view to save image to the media folder and store the image path in the model:

    from django.core.files.uploadedfile import SimpleUploadedFile
    import os
    
    def upload_drawings(request):
        if request.method == "POST":
            form  = DrawingPDFForm(request.POST, request.FILES)
            drawing_name = request.POST['drawing_name']
            file = request.FILES['file']
            
            # Convert PDF to PNG
            pdf_byt = file.read()
            pdf_content = BytesIO(pdf_byt) 
            pdf_content.seek(0)
            pdf_converted = convert_from_bytes(pdf_content.read(), poppler_path=r"C:\Python\Python\Programs\plant_locator\poppler\poppler-23.07.0\Library\bin")
            buffer = BytesIO()
            pdf_converted[0].save(buffer, 'png')
            
            # Save PNG to the media folder
            png_byt = buffer.getvalue()
            drawing_path = os.path.join('images', f'{drawing_name}.png')
            drawing_file = SimpleUploadedFile(drawing_path, png_byt, content_type='image/png')
            
            # Create and save the Drawing instance
            drawing = Drawing.objects.create(drawing_name=drawing_name, drawing=drawing_file)
            
            return HttpResponseRedirect('/upload_drawings')
        else:
            form = DrawingPDFForm()
            
        return render(request, 'upload_drawings.html', {'form': form})
    

    and make sure you have configured the media settings in your django project:

    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    

    I hope this helps you.