Хотите загрузить изображение с помощью пользовательской функции загрузки изображения python djano
Это моя пользовательская функция загрузки изображений
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)
а это моя модель
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}'
Я хочу загрузить изображение с помощью моей функции upload_image, и, как вы видите, она принимает 3 параметра file, dir_name и имя_файла. Как я могу передать эти параметры в model.ImageField()? Также я хочу сохранить image_url в моей базе данных, как возвращается функцией upload_image, будет ли она сохранять файл в БД или URL?
Прежде всего, вы должны передать upload_image, а не вызов upload_image():
image_url = models.ImageField(upload_to=upload_image)
Во-вторых, upload_to автоматически вызывает Storage.save() с переданным значением. Поэтому вызов внутри upload_image() не нужен. upload_image должен возвращать только путь, по которому должен быть сохранен файл.
функция upload_to должна принимать 2 параметра, instance и filename.
Вот мое решение для хранения файлов.
Вы просто реализуете приведенную ниже функцию и используете ее в модели.
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]
например:
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")
)
Для того, чтобы передать имя функции, сначала нужно написать функцию в модели, которая обрабатывает путь, вот так !
# 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}'
Ну, я просто собираюсь подсказать вам, как вы можете поступить в этой ситуации, вы можете рефакторить свой код, так как это будет работать в том же смысле. вот мое решение о том, как написать свой пользовательский вид:
# 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