如何在 Django 中處理用戶圖片並自動轉換為 WebP 格式

更新日期: 2024 年 12 月 21 日

在現代的 web 開發中,圖片的高效處理對於提升網站性能至關重要。

WebP 格式因其優異的壓縮能力,已成為優化圖片加載速度的最佳選擇之一。

本篇文章將教您如何在 Django 中實現用戶圖片的上傳與管理,並通過自動轉換為 WebP 格式,將優化後的圖片存儲到 AWS S3。


目標功能

本文的代碼將實現以下功能:

  1. 用戶可以上傳個人圖片。
  2. 系統將圖片自動轉換為 WebP 格式。
  3. 處理後的圖片自動上傳到 AWS S3。
  4. 模型中的圖片字段自動更新為存儲在 S3 上的 WebP 圖片的 URL。

完整代碼

以下是完整的 Profile 模型代碼,實現上述功能:

from django.db import models
from django.contrib.auth.models import User
from PIL import Image
from io import BytesIO
import boto3
import uuid
from django.conf import settings


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
    photo = models.ImageField(upload_to="profile_photos/", blank=True, null=True)
    bio = models.TextField(max_length=200, null=True)
    location = models.CharField(max_length=50, null=True)
    is_client = models.BooleanField(default=True, null=True)
    is_freelancer = models.BooleanField(default=False, null=True)
    freelancer_verified = models.BooleanField(default=False, null=True)

    def save(self, *args, **kwargs):
        """
        保存模型時,自動將上傳的圖片轉換為 WebP 格式並上傳到 AWS S3,
        同時將 photo 字段更新為 WebP 圖片的 S3 URL。
        """
        # 保存原始圖片,確保能獲取文件對象
        super().save(*args, **kwargs)

        if self.photo:  # 確保 photo 字段存在
            try:
                # 打開圖片並轉換為 WebP 格式
                image = Image.open(self.photo)
                webp_image_io = BytesIO()
                image.save(webp_image_io, format="WEBP", quality=85)
                webp_image_io.seek(0)

                # 生成唯一文件名
                unique_filename = f"profile_photos/{uuid.uuid4()}.webp"

                # 上傳到 S3
                s3 = boto3.client('s3', region_name=settings.AWS_S3_REGION_NAME)
                s3.upload_fileobj(
                    webp_image_io,
                    settings.AWS_STORAGE_BUCKET_NAME,
                    unique_filename,
                    ExtraArgs={"ContentType": "image/webp"}
                )

                # 覆蓋 photo 字段為 WebP 文件的 S3 URL
                self.photo.name = unique_filename

                # 再次保存模型,更新 photo 字段
                super().save(*args, **kwargs)
            except Exception as e:
                print(f"圖片處理或上傳失敗:{e}")

    def __str__(self):
        """
        返回用戶名及其 Profile 的表示。
        """
        return f"{self.user.username}'s Profile"

功能解析

模型字段介紹

  • user 字段
    定義 Profile 與內建 User 模型的一對一關係,讓每個用戶對應一個 Profile
  • photo 字段
    儲存上傳的用戶圖片。圖片將存放於 profile_photos/ 文件夾下,並支持空值。
  • 其他字段
    • biolocation:分別用於儲存用戶簡介和地理位置。
    • is_clientis_freelancer:標識用戶的角色類型。
    • freelancer_verified:標記自由職業者的驗證狀態。

自定義 save() 方法

圖片處理與存儲的完整流程:

  1. 保存原始圖片
    調用父類的 save() 方法,先保存用戶上傳的原始圖片。
  2. 轉換為 WebP 格式
    使用 Pillow 庫將圖片轉換為 WebP 格式,並將處理後的圖片保存在內存中。
  3. 生成唯一文件名
    為每張圖片生成唯一的文件名,避免因重名導致的衝突。
  4. 上傳到 AWS S3
    使用 boto3 將圖片文件流上傳到指定的 AWS S3 存儲桶,並設置 MIME 類型為 image/webp
  5. 更新模型字段
    photo 字段的值更新為存儲在 S3 上的 WebP 圖片 URL,並再次保存模型。

AWS S3 的設置依賴

在使用該代碼之前,請確保已經在 settings.py 文件中正確配置了 AWS S3 的相關參數:

AWS_S3_REGION_NAME = "your-region"  # 例如 "us-east-1"
AWS_STORAGE_BUCKET_NAME = "your-bucket-name"
AWS_ACCESS_KEY_ID = "your-access-key"
AWS_SECRET_ACCESS_KEY = "your-secret-key"

優化建議

  1. 增加異常處理
    如果圖片處理或上傳過程中出現問題(例如網絡錯誤),可以記錄日誌或返回友好的錯誤信息。
  2. 性能優化
    • 減少圖片處理過程中的 I/O 操作。
    • 在高並發環境中,可以使用任務隊列(如 Celery)將圖片處理與上傳操作異步化。
  3. 圖片大小限制
    可以在上傳時驗證圖片大小,避免過大的文件影響系統性能。

結論

通過本文的實現,您可以輕鬆完成用戶圖片的上傳、轉換和存儲,並充分利用 WebP 格式的優勢提升應用性能。

同時,整合 AWS S3 讓圖片管理更加方便高效。希望這篇文章能為您提供有價值的參考,助力構建更優化的圖片處理功能!

Similar Posts