'Want to upload an image using a custom upload image function python djano

This is my custom image upload function

def upload_image(file, dir_name, filename):
    try:
        target_path = '/static/images/' + dir_name + '/' + filename
        path = storage.save(target_path, file)
        return storage.url(path)
    except Exception as e:
        print(e)

and this is my model

class MenuOptions(models.Model):
    name = models.CharField(max_length=500, null=False)
    description = models.CharField(max_length=500, null=True)
    image_url = models.ImageField(upload_to=upload_image())

    def __str__(self):
        return f'{self.name}'

I want to upload the image using my upload_image function, and as you can see it is taking 3 parameters file,dir_name, and the file_name. how can I pass these parameters in my model.ImageField() Also, I want to store the image_url to my database as returned by the upload_image function will it store the file in DB or the URL?



Solution 1:[1]

First of all, you should pass upload_image, not a call to upload_image():

image_url = models.ImageField(upload_to=upload_image)

Second thing, upload_to automatically calls Storage.save() with the passed value. Therefore call inside upload_image() is not needed. upload_image should only return path, where file is supposed to be saved.

function upload_to should take 2 parameters, instance and filename.

reference

Solution 2:[2]

This is my solution for storing files.

You just implement the below function and use it in the model.

import os
import uuid
from django.utils.deconstruct import deconstructible


@deconstructible
class MediaFileNameHash(object):
    def __init__(self, base_dir, path):
        self.address = base_dir + "/" + path
        self.path = path
        if not os.path.exists(self.address):
            os.makedirs(self.address, exist_ok=True)

    def __call__(self, _, filename):
        # @note It's up to the validators to check if it's the correct file type in name or if one even exist.
        filename = os.path.splitext(filename)
        return self.path + '/' + filename[0] + "@" + str(uuid.uuid4()) + filename[1]

for example:

class MenuOptions(models.Model):
    name = models.CharField(max_length=500, null=False)
    description = models.CharField(max_length=500, null=True)
    image_url = models.ImageField(
         upload_to=MediaFileNameHash("/media/", "files"),
         verbose_name=_("Address")
    )

Solution 3:[3]

In other to pass the function name you first of all need to write a function in the model that handles the path like this !

# In you models.py 
# will automatically save your image to your custom view 

def get_upload_image_filepath(self, filename):
    return 'Images/' + str(self.pk) + '/default.png'

class MenuOptions(models.Model):
    name = models.CharField(max_length=500, null=False)
    description = models.CharField(max_length=500, null=True)
    image_url = models.ImageField(upload_to=get_upload_image_filepath)

    def __str__(self):
        return f'{self.name}'

Well am just going to guide you toward how you can go about this situation , you could refactor your code as it would work in the same sense. this is my solution on how to write your custom view:

# this would be at the top of your view 
import base64
import os

TEMP_UPLOAD_IMAGE_NAME = "default.png"


def save_temp_upload_image_from_base64String(imageString, user):
    INCORRECT_PADDING_EXCEPTION = "Incorrect padding"
    try:
        if not os.path.exists(settings.TEMP):
            os.mkdir(settings.TEMP)
        if not os.path.exists(settings.TEMP + "/" + str(user.pk)):
            os.mkdir(settings.TEMP + "/" + str(user.pk))
        url = os.path.join(settings.TEMP + "/" + str(user.pk),TEMP_UPLOAD_IMAGE_NAME)
        storage = FileSystemStorage(location=url)
        image = base64.b64decode(imageString)
        with storage.open('', 'wb+') as destination:
            destination.write(image)
            destination.close()
        return url
    except Exception as e:
        print("exception: " + str(e))
        # workaround for an issue I found
        if str(e) == INCORRECT_PADDING_EXCEPTION:
            imageString += "=" * ((4 - len(imageString) % 4) % 4)
            return save_temp_upload_image_from_base64String(imageString, user)
    return None

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Blomex
Solution 2 rmaleki
Solution 3