【问题标题】:Want to upload an image using a custom upload image function python djano想要使用自定义上传图片功能 python django 上传图片
【发布时间】:2022-01-24 11:25:13
【问题描述】:

这是我的自定义图片上传功能

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 和file_name。 如何在我的 model.ImageField() 中传递这些参数 另外,我想将 image_url 存储到我的数据库中,就像 upload_image 函数返回的那样,它将文件存储在 DB 中还是 URL 中?

【问题讨论】:

  • 您不需要在upload_image 函数中使用.save() 图像。它应该只返回应该保存的路径。
  • 我正在将它上传到谷歌存储,所以我将不得不调用 .save() 方法。

标签: python-3.x django django-models django-views django-forms


【解决方案1】:

首先,你应该传递upload_image,而不是调用upload_image()

image_url = models.ImageField(upload_to=upload_image)

第二件事,upload_to 自动使用传递的值调用Storage.save()。因此不需要在upload_image() 内调用。 upload_image 应该只返回应该保存文件的路径。

函数upload_to应该有两个参数,instancefilename

reference

【讨论】:

  • Upload_image() 将图像保存在谷歌云存储中,这就是使用 storage.save() 的原因。另外,“文件”参数是谷歌云存储方法的要求,所以我也必须传递文件。
  • from storages.backends.gcloud import GoogleCloudStoragestorage = GoogleCloudStorage()
【解决方案2】:

这是我存储文件的解决方案。

你只需实现下面的函数并在模型中使用它。

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")
    )

【讨论】:

  • Goog 解决方案,但不适合我的用例,因为 upload_image() 函数是通用函数,我将不得不在其他 10 个地方使用它,还将图像存储到谷歌云存储存储桶但不在本地存储中
  • 好的,谢谢。 @Theknight
【解决方案3】:

为了传递函数名,你首先需要在模型中编写一个函数来处理这样的路径!

# 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-28
    • 2013-08-17
    • 1970-01-01
    • 2023-02-08
    • 2014-03-20
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    相关资源
    最近更新 更多