Image Upload with Forms

A snippet showing how to handle image uploads with forms.


# Install Pillow (required for ImageField)
pip install Pillow
      

# forms.py

from django import forms

ALLOWED_TYPES = {"image/jpeg", "image/png", "image/webp"}

class AvatarForm(forms.Form):
    image = forms.ImageField()

    def clean_image(self):
        img = self.cleaned_data.get("image")
        if not img:
            return img

        # Size check (2 MB)
        max_mb = 2
        if img.size > max_mb * 1024 * 1024:
            raise forms.ValidationError(f"Image too large. Max {max_mb} MB allowed.")

        # Content type check
        ctype = getattr(img, "content_type", None)
        if ctype not in ALLOWED_TYPES:
            raise forms.ValidationError("Only JPEG, PNG, or WEBP images are allowed.")

        return img
      

# views.py

from django.shortcuts import render
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from .forms import AvatarForm

def avatar_upload(request):
    path = None
    if request.method == "POST":
        form = AvatarForm(request.POST, request.FILES)
        if form.is_valid():
            f = form.cleaned_data["image"]
            path = default_storage.save(f"avatars/{f.name}", ContentFile(f.read()))
    else:
        form = AvatarForm()

    return render(request, "avatar_upload.html", {"form": form, "path": path})
      


<div class="row justify-content-center">
  <div class="col-md-8 col-lg-6">
    <form method="post" enctype="multipart/form-data" class="bg-white border rounded p-3">
      {% csrf_token %}
      <h5 class="mb-3">Upload avatar</h5>
      {{ form.as_p }}
      <button type="submit" class="btn btn-primary w-100">Upload</button>
    </form>

    {% if path %}
      <div class="alert alert-success mt-3">
        <div>Saved to: <code>{{ path }}</code></div>
        <img src="{{ MEDIA_URL }}{{ path|cut:'media/' }}" class="img-fluid mt-2" alt="Uploaded avatar">
      </div>
    {% endif %}
  </div>
</div>
  
Explanation:
  • ImageField requires Pillow; validate size and content_type for safety.
  • In production, serve media via a web server or object storage; avoid Django for large files.
  • When using reverse proxies, ensure MEDIA_URL is correctly mapped to MEDIA_ROOT.
  • Category Forms & Validation
  • Total Views 610
  • Last Modified 08 December, 2025
  • Tags #forms #image upload #media #validation
Never miss a story on Django.wiki

Subscribe for fresh tutorials, snippets, and updates.

By subscribing you agree to our Privacy Policy.