OUJOOD.COM
Configurer les fichiers médias dans settings.py
Django distingue les fichiers statiques (CSS, JS, images fixes) des fichiers médias (fichiers uploadés par les utilisateurs). Ces derniers sont stockés dans un dossier séparé et servis via une URL dédiée. Deux paramètres dans settings.py :
# settings.py import os # URL préfixe pour accéder aux fichiers médias MEDIA_URL = '/media/' # Dossier où Django stocke les fichiers uploadés MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Il faut aussi déclarer cette URL dans urls.py du projet pour que Django serve les médias en développement :
# monprojet/urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('membres/', include('membres.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Remarque : static() ne sert les médias que si DEBUG = True. En production, c'est le serveur web (Nginx, Apache) ou un service de stockage (AWS S3) qui prend en charge cette tâche.
Ajouter un champ de fichier au modèle
FileField stocke n'importe quel type de fichier. ImageField est une spécialisation qui vérifie que le fichier uploadé est bien une image (nécessite la bibliothèque Pillow).
from django.db import models
class Membres(models.Model):
prenom = models.CharField(max_length=255)
nom = models.CharField(max_length=255)
mail = models.EmailField()
# upload_to définit le sous-dossier dans MEDIA_ROOT
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
cv = models.FileField(upload_to='documents/cv/', blank=True, null=True)
Le paramètre upload_to peut être une chaîne fixe ou une fonction qui génère un chemin dynamique. Les fichiers seront stockés dans MEDIA_ROOT/avatars/ et MEDIA_ROOT/documents/cv/.
Installez Pillow si vous utilisez ImageField :
pip install Pillow
Après avoir modifié le modèle, lancez les migrations :
python manage.py makemigrations python manage.py migrate
Créer le formulaire d'upload
Un ModelForm suffit — Django génère automatiquement un FileInput pour les champs fichiers :
from django import forms
from .models import Membres
class MembreForm(forms.ModelForm):
class Meta:
model = Membres
fields = ['prenom', 'nom', 'mail', 'avatar', 'cv']
Traiter l'upload dans la vue
La différence essentielle avec un formulaire texte : les fichiers uploadés arrivent dans request.FILES, pas dans request.POST. Il faut passer les deux au formulaire.
from django.shortcuts import render, redirect, get_object_or_404
from .forms import MembreForm
def ajouter_membre(request):
if request.method == 'POST':
# request.FILES est obligatoire pour les formulaires avec fichiers
form = MembreForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('index')
else:
form = MembreForm()
return render(request, 'ajout.html', {'form': form})
def modifier_membre(request, id):
membre = get_object_or_404(Membres, id=id)
if request.method == 'POST':
form = MembreForm(request.POST, request.FILES, instance=membre)
if form.is_valid():
form.save()
return redirect('index')
else:
form = MembreForm(instance=membre)
return render(request, 'modifier.html', {'form': form})
Le template — enctype obligatoire
Un formulaire qui contient un champ fichier doit avoir l'attribut enctype="multipart/form-data" sur la balise <form>. Sans lui, le fichier ne sera jamais transmis au serveur.
<!DOCTYPE html>
<html>
<body>
<h1>Ajouter un membre</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Enregistrer</button>
</form>
</body>
</html>
Afficher un fichier uploadé dans le template
Django stocke le chemin du fichier en base de données. L'attribut .url génère l'URL complète à partir de MEDIA_URL :
{% if membre.avatar %}
<img src="{{ membre.avatar.url }}" alt="Avatar de {{ membre.prenom }}">
{% else %}
<p>Aucun avatar.</p>
{% endif %}
{% if membre.cv %}
<a href="{{ membre.cv.url }}">Télécharger le CV</a>
{% endif %}
Testez toujours {% if membre.avatar %} avant d'utiliser .url — si le champ est vide, appeler .url lève une exception.
Par carabde | Mis à jour le 06 mai 2026