You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django REST Framework中用Pillow压缩用户上传图片

Compressing User-Uploaded Images with Pillow in Django REST Framework

Hey there! Let's walk through how to add automatic image compression to your Django REST Framework project using Pillow, specifically modifying your existing Photo model to handle this whenever users upload images.

Prerequisite: Install Pillow

First, make sure you have Pillow installed—if not, run this command in your virtual environment:

pip install pillow

Approach: Override the Model's save() Method

The cleanest way to handle image compression is to override your Photo model's save() method. This ensures compression runs every time an image is uploaded or updated, whether it's via the DRF API, admin panel, or any other part of your app.

Here's your modified Photo model with compression logic:

from PIL import Image
from django.conf import settings
from django.db import models

class Photo(models.Model):
    title = models.CharField(max_length=100)
    uploader = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
    image_url = models.ImageField(upload_to='images', null=True)

    def save(self, *args, **kwargs):
        # Track if we're dealing with a new image or an updated one
        is_new_image = self.pk is None
        old_image_path = None

        if not is_new_image:
            # Grab the original image path before saving changes
            original_photo = Photo.objects.get(pk=self.pk)
            old_image_path = original_photo.image_url.path if original_photo.image_url else None

        # Save the model first to ensure the image is stored on disk
        super().save(*args, **kwargs)

        # Only compress if the image was added or changed
        if self.image_url and (is_new_image or self.image_url.path != old_image_path):
            try:
                # Open the uploaded image file
                with Image.open(self.image_url.path) as img:
                    # Define your compression preferences
                    max_dimension = 1200  # Max width/height (adjust to your needs)
                    quality = 70  # JPEG quality (1-100; lower = smaller file size)

                    # Resize the image while preserving aspect ratio
                    if img.width > max_dimension or img.height > max_dimension:
                        img.thumbnail((max_dimension, max_dimension), Image.Resampling.LANCZOS)
                        # LANCZOS is a high-quality resampling filter for crisp resizes

                    # Save the compressed image back to the same path
                    img.save(
                        self.image_url.path,
                        optimize=True,  # Removes unnecessary metadata
                        quality=quality,
                        format=img.format  # Keep the original image format
                    )
            except Exception as e:
                # Handle errors (e.g., corrupted image files) without breaking the save
                print(f"Error compressing image: {str(e)}")

Key Details Explained:

  • Avoid Re-Compression: We only process images when they're new or have been updated—this prevents re-compressing the same image every time you edit the title or other fields.
  • Smart Resizing: The thumbnail() method maintains the image's aspect ratio while shrinking it to fit within your max_dimension limits, using a high-quality filter to avoid pixelation.
  • Quality Control: The quality parameter adjusts JPEG compression balance (lower values mean smaller files, slightly reduced quality). optimize=True strips extra metadata to further cut file size.
  • Error Safety: Wrapping the image processing in a try-except block ensures the model still saves even if something goes wrong with the image (like a corrupted file).

How It Works with DRF

When a user uploads an image via your DRF API, the serializer will create/update a Photo instance. The overridden save() method automatically triggers compression right after the image is saved to your filesystem. No extra changes are needed in your serializers or views—this logic lives entirely at the model level.

Optional Enhancements

  • Convert to WebP: For even better compression, change the format parameter to 'WEBP' in img.save() (WebP files are 25-35% smaller than JPEGs with similar quality).
  • Per-User Settings: Add a model field to let users choose compression quality, or set different rules for different image types.
  • Async Processing: For large images, offload compression to a background task (using Celery, for example) to avoid slowing down API responses.

内容的提问来源于stack exchange,提问作者Naterz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 11:27:31