使用基類模型(class model)優化代碼:從零到掌握 DRY 原則
更新日期: 2024 年 12 月 26 日
本文為圖片轉 WebP 功能模組化系列文,第 3 篇:
- 如何設計 Django 的通用工具,並選擇適合的存放位置
- 從零開始:如何實現圖片轉 WebP 並上傳到 S3 的功能
- 使用基類模型(class model)優化代碼:從零到掌握 DRY 原則 👈 所在位置
- Django 抽象模型:理解 class Meta: abstract = True
- 為什麼要分離圖片處理邏輯?Django 最佳實踐指南
- Django 信號處理:如何在保存前自動處理圖片
- Django 信號處理的最佳實踐:如何選擇合適的位置
- 將圖片處理移至信號:模型設計的最佳實踐
- 理解 Python 的方法解析順序 (MRO):Django 多重繼承的最佳實踐
建議閱讀本文前,先閱讀完 圖片轉 WebP 系列文
在開發過程中,重複代碼會增加維護成本,降低可讀性和擴展性。
通過基類模型(class model)或工具類的抽象化設計,我們可以將重複邏輯集中管理,實現代碼的高效重用。
這篇文章將帶你學習如何使用基類模型優化圖片處理邏輯,並實現符合 DRY (Don’t Repeat Yourself) 原則的代碼結構。
問題背景
目前,在項目中的多個模型(如 Profile
和其他圖片相關模型)存在一些重複邏輯,例如:
- 圖片的 WebP 格式轉換與上傳到 S3。
- 原始文件的清理和管理。
這些重複代碼會導致維護成本上升,尤其當邏輯需要更新時,開發者需要在多處修改代碼,增加出錯風險。
解決方案是將這些邏輯抽象到一個通用的基類模型中,讓模型專注於自身業務邏輯,而通用功能交給基類處理。
創建通用的基類模型
為了解決上述問題,我們設計了一個名為 WebPImageModelMixin
的基類,用於管理圖片的 WebP 處理與 S3 文件管理邏輯。
mixins.py
from django.db import models
from utils.image_processing import convert_and_upload_to_webp
import boto3
from django.conf import settings
class WebPImageModelMixin(models.Model):
"""
用於將圖片轉換為 WebP 格式並上傳到 S3 的基類
"""
class Meta:
abstract = True
def process_and_upload_image(self, image_file, folder_name):
"""
將圖片轉換為 WebP 格式並上傳到 S3,同時清理原始圖片。
參數:
- image_file: 要處理的圖片檔案
- folder_name: S3 存儲文件夾名稱
返回:
- 處理後圖片的 S3 路徑
"""
original_filename = image_file.name
new_image_path = convert_and_upload_to_webp(image_file, folder_name)
image_file.name = new_image_path
# 從 S3 中刪除原始文件
if original_filename:
s3 = boto3.client("s3", region_name=settings.AWS_S3_REGION_NAME)
s3.delete_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=original_filename)
這段代碼提供了以下功能:
- 將圖片轉換為 WebP 格式。
- 將新圖片上傳到 S3。
- 自動清理原始文件。
應用方式:以基類邏輯更新模型
在設計好基類後,我們可以讓需要圖片處理功能的模型(如 Profile
和 ServiceImage
)繼承基類 WebPImageModelMixin
,以實現代碼邏輯的集中管理。
Profile
模型示例
以下是修改後的 Profile
模型代碼,它繼承了基類並應用了通用邏輯:
from django.contrib.auth.models import User
from django.db import models
from mixins import WebPImageModelMixin
class Profile(WebPImageModelMixin, 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):
super().save(*args, **kwargs)
if self.photo:
self.process_and_upload_image(self.photo, "profile_photos/")
def __str__(self):
return f"{self.user.username}'s Profile"
在 save
方法中,圖片的處理和上傳交由基類方法 process_and_upload_image
完成,避免了冗餘的代碼。
設計優化的好處
更乾淨的代碼
模型只需關注核心功能,例如字段定義與業務邏輯,圖片的處理與 S3 文件管理的細節由基類處理。
更高的重用性
任何需要圖片處理的模型,只需繼承 WebPImageModelMixin
,並在適當的位置調用基類方法即可實現同樣的功能。
更好的維護性
當圖片處理邏輯需要修改時,只需在基類中進行更新,所有繼承基類的模型都會自動同步改動,減少了重複修改的工作量。
總結
通過將圖片的處理邏輯抽象到通用的基類模型中,我們實現了代碼的高效重用,符合 DRY 原則的最佳實踐。
不僅提升了代碼的可讀性和維護性,還大幅度減少了重複邏輯的出現。
現在,你可以將這一方法應用到你的項目中,為每一個需要圖片處理的模型提供統一的解決方案,提升開發效率!