首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >图像缩略图Django Backblaze B2

图像缩略图Django Backblaze B2
EN

Stack Overflow用户
提问于 2019-01-16 00:50:51
回答 1查看 535关注 0票数 0

我正在建设一个图片浏览和存储网站使用Django和Backblaze B2,我有很多大(文件大小)的照片,我计划上传到它。

我的计划是使用缩略图进行图片浏览,这些需要自动生成。照片被上传到Django,而Django又将照片上传到B2,然后再下载,创建缩略图并将缩略图上传到B2。

下载完整大小的映像步骤对我来说似乎是不安全的,因为文件已经通过Django The服务器上传。Django就不能把上传的照片保存在内存(或临时本地存储)中,构建一个缩略图,然后将全尺寸图像和缩略图上传到B2吗?

我正在使用下面的代码在save()模型的Photo步骤中生成一个缩略图,它可以工作。我只是在寻找一种方法,使这个更有效,而不下载全尺寸的图像再次。我考虑在PhotoForm中使用重写的save()方法来完成这个任务,但是我无法找到如何做到这一点。我还包括了自定义B2Storage类的代码。

如果有人能给我一个我应该采取的方法,我会非常感激的。谢谢!

模型/照片.photo.py

代码语言:javascript
复制
import os
from io import BytesIO

from PIL import Image
from django.core.files.base import ContentFile
from django.db import models

from fotoplatform.storage import B2Storage

THUMB_SIZE = (400, 400)


class Photo(models.Model):
    title = models.CharField(max_length=50)
    photo = models.ImageField(storage=B2Storage(), unique=True)
    thumbnail = models.ImageField(storage=B2Storage(), unique=True)

    def save(self, *args, **kwargs):
        if not self.thumbnail:
             self.make_thumbnail()
        super(Photo, self).save(*args, **kwargs)

    def make_thumbnail(self):
        try:
            image = Image.open(self.photo)
        except:
            raise Exception('Unable to open photo')

        image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)

        thumb_name, thumb_extension = os.path.splitext(self.photo.name)
        thumb_extension = thumb_extension.lower()

        thumb_filename = thumb_name + '_thumb' + thumb_extension

        if thumb_extension in ['.jpg', '.jpeg']:
            FTYPE = 'JPEG'
        elif thumb_extension == '.gif':
            FTYPE = 'GIF'
        elif thumb_extension == '.png':
            FTYPE = 'PNG'
        else:
            raise Exception("Unknown extension")

        temp_thumb = BytesIO()
        image.save(temp_thumb, FTYPE)
        temp_thumb.seek(0)

        self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)
        temp_thumb.close()

forms.py

代码语言:javascript
复制
import logging

from django import forms

from fotoplatform.models import Photo


class PhotoForm(LoggingMixin, forms.ModelForm):
    photo = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

    class Meta:
        model = Photo
        fields = ['title', 'photo']

storage.py

代码语言:javascript
复制
import hashlib
import logging
import os
import re

from b2blaze import B2
from django.core.files.storage import Storage
from django.utils.deconstruct import deconstructible

from dsbfotoplatform import settings

logger = logging.getLogger(__name__)

b2 = B2(key_id=settings.B2_KEY_ID, application_key=settings.B2_APPLICATION_KEY)
bucket = b2.buckets.get(bucket_id=settings.B2_BUCKET_ID)

@deconstructible
class B2Storage(Storage):

    def path(self, name):
        pass

    def delete(self, name):
        pass

    def exists(self, name):
        pass

    def listdir(self, path):
        pass

    def size(self, name):
        pass

    def get_accessed_time(self, name):
        pass

    def get_created_time(self, name):
        pass

    def get_modified_time(self, name):
        pass

    def _open(self, name, mode='rb'):
        file = bucket.files.get(file_name=name)
        return file.download()

    def _save(self, name, content):
        name = self.generate_filename(name)
        name = "photos/" + name
        bucket.files.upload(contents=content, file_name=name)
        return name

    def generate_filename(self, filename):
        filename, file_extension = os.path.splitext(filename)
        m = hashlib.md5()
        m.update(filename.encode("UTF-8"))
        return m.hexdigest() + file_extension

    def url(self, name):
        url = re.sub(r'b2api.*$', '', bucket.connector.download_url)
        url += "fotoplatform/" + name
        return url
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-23 16:21:55

同时,我想出了一个合理的解决方案。我正在创建一个带有照片文件和其他我想要存储的数据的TempPhoto对象。我将照片存储在运行Django的服务器上,保存在temp_photos文件夹中。然后,在创建TempPhoto对象之后调用一个芹菜任务,并向上传浏览器返回一个成功响应。

芹菜任务在后台开始运行,同时,这将创建一个真实的Photo对象,并使用在我的问题中描述的make_thumbnail(self)方法生成所需的缩略图。然后,它会上传B2所需的所有内容。这可能会占用每张照片1分钟的时间,有时是Backblaze B2的慢API,但这并不重要,因为它现在是在后台异步运行,独立于Django per服务器。在此任务结束时,TempPhoto对象被删除,temp_photo中本地存储的照片也被删除。

我正在研究一种将任务进度转回给最终用户的方法,但这一点现在并不太重要。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54208947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档