如何避免重複存儲不同格式圖片在 AWS S3:新手指南
更新日期: 2024 年 12 月 21 日
本文為 Django 圖片轉 webp 系列教學,第 10 篇:
- 圖片轉換為 WebP 格式並存儲到 AWS S3 的完整指南
- 如何決定儲存 WebP 圖片的方式:覆蓋與直接存儲解析
- 如何在 Django 中處理用戶圖片並自動轉換為 WebP 格式
- 使用 Django 和 AWS S3 實現圖片存儲:基礎指南
- 如何在 Django 中使用 Pillow 處理圖片並轉換為 WebP 格式
- 如何使用 UUID 為圖片生成唯一文件名:Django 文件處理實例
- 使用 Boto3 將 WebP 圖片上傳到 AWS S3:完整指南
- 解決 AWS S3 HeadObject 錯誤 (403 Forbidden):詳細指南
- 解決圖片重複上傳到 AWS S3 的問題:給新手的指南
- 如何避免重複存儲不同格式圖片在 AWS S3:新手指南 👈 所在位置
- 理解 Django 文件字段的行為:新手指南
建議閱讀本文前,先閱讀完 圖片上傳 AWS 功能 系列文
在處理圖片上傳時,我們經常需要將圖片轉換為更高效的格式(如 WebP)以提升性能。
然而,如果處理後的圖片(WebP)與原始圖片(PNG、JPG)都存儲在 AWS S3 中,可能會導致存儲空間浪費和管理負擔。
本指南旨在幫助新手學習如何在圖片轉換完成後,刪除原始圖片,確保只有處理後的 WebP 文件被保留。
問題分析:圖片重複存儲的原因
當我們使用 Django 上傳圖片並進行格式轉換時,常見的邏輯流程如下:
- 用戶上傳圖片(例如
example.jpg
)。 - 圖片被保存到 AWS S3。
- 圖片轉換為 WebP 格式後,處理後的文件(如
example.webp
)也被上傳到 S3。 - 但此時,原始文件(
example.jpg
)並未被刪除。
這會導致同一張圖片存在兩個版本(原始和處理後),既浪費了存儲空間,也讓管理變得複雜。
解決方法:上傳 WebP 文件後刪除原始圖片
我們可以在處理完成後,使用 AWS S3 的 delete_object
方法刪除原始圖片。
修改 save()
方法
下面是一個完整的代碼示例,展示如何在轉換 WebP 文件後刪除原始文件。
from io import BytesIO
from PIL import Image
import boto3
import uuid
from django.conf import settings
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(upload_to="profile_photos/", blank=True, null=True)
def save(self, *args, **kwargs):
# 保存模型其他字段
super().save(*args, **kwargs)
if self.photo:
try:
# 打開原始圖片
image = Image.open(self.photo)
# 將圖片轉換為 WebP
webp_image_io = BytesIO()
image.save(webp_image_io, format="WEBP", quality=85)
webp_image_io.seek(0)
# 生成 WebP 文件唯一名稱
unique_filename = f"profile_photos/{uuid.uuid4()}.webp"
# 初始化 S3 客戶端
s3 = boto3.client("s3", region_name=settings.AWS_S3_REGION_NAME)
# 上傳 WebP 文件到 S3
s3.upload_fileobj(
webp_image_io,
settings.AWS_STORAGE_BUCKET_NAME,
unique_filename,
ExtraArgs={"ContentType": "image/webp"},
)
# 獲取原始檔案的路徑
original_file_path = self.photo.name
# 更新 photo 字段為新的 WebP 文件路徑
self.photo = unique_filename
# 保存更新後的 photo 字段
super().save(*args, **kwargs)
# 刪除原始檔案
s3.delete_object(
Bucket=settings.AWS_STORAGE_BUCKET_NAME,
Key=original_file_path,
)
except Exception as e:
raise RuntimeError(f"Error converting image to WebP: {e}")
詳細解釋代碼邏輯
步驟 1:保存模型其他字段
super().save(*args, **kwargs)
- 先保存模型的其他字段(例如名稱、描述等),確保基本信息被保存。
步驟 2:處理圖片
- 使用 Pillow 打開原始圖片,並將其轉換為 WebP 格式:
image = Image.open(self.photo)
webp_image_io = BytesIO()
image.save(webp_image_io, format="WEBP", quality=85)
webp_image_io.seek(0)
步驟 3:生成唯一文件名
- 使用 UUID 生成不重複的文件名:
unique_filename = f"profile_photos/{uuid.uuid4()}.webp"
步驟 4:上傳 WebP 文件
- 使用 AWS S3 的
upload_fileobj
方法上傳處理後的圖片:
s3.upload_fileobj(
webp_image_io,
settings.AWS_STORAGE_BUCKET_NAME,
unique_filename,
ExtraArgs={"ContentType": "image/webp"},
)
步驟 5:刪除原始文件
- 使用
delete_object
方法刪除原始文件:
original_file_path = self.photo.name
s3.delete_object(
Bucket=settings.AWS_STORAGE_BUCKET_NAME,
Key=original_file_path,
)
測試場景
情境 1:上傳新圖片
- 用戶上傳圖片(如
example.jpg
)。 - 程式保存該圖片,轉換為 WebP 格式(如
example.webp
),並刪除原始文件。
情境 2:更新圖片
- 用戶上傳新的圖片(如
new_example.jpg
)。 - 程式保存新圖片,生成新的 WebP 文件,刪除新的原始文件。
情境 3:未更改圖片
- 如果用戶未更改圖片,
self.photo
未更新,圖片處理邏輯不會被執行,也不會刪除任何文件。
注意事項
權限設置
- 確保 AWS S3 的 IAM 策略允許刪除操作:
{ "Effect": "Allow", "Action": "s3:DeleteObject", "Resource": "arn:aws:s3:::your-bucket-name/*" }
錯誤處理
- 如果刪除原始文件失敗,建議記錄錯誤日誌以便後續排查。
節省成本
- 通過刪除原始文件,可以節省存儲成本,特別是在大規模圖片處理場景中。
總結
通過在圖片轉換後刪除原始文件,我們可以有效地避免同一張圖片的多個版本被存儲,從而節省存儲空間並簡化管理。
本文介紹的方法適合各類需要進行圖片處理和雲存儲的應用場景,希望對新手開發者有所幫助。