Envoi de fichiersLien vers cette rubrique

Lorsque Django gère un téléversement de fichier, les données du fichier aboutissent dans request.FILES (plus de détails sur l’objet request se trouvent dans la documentation des objets request et response). Ce document explique comment les fichiers sont stockés sur disque et en mémoire, et comment personnaliser le comportement par défaut.

Envoi simple de fichiersLien vers cette rubrique

Consider a simple form containing a FileField:

forms.py
Code
from django import forms

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=50)
    file = forms.FileField()

Une vue gérant ce formulaire recevra les données de fichier dans request.FILES qui est un dictionnaire contenant une clé pour chaque FileField (ou ImageField, ou toute autre sous-classe de FileField) du formulaire. Ainsi, les données du formulaire ci-dessus seraient accessibles dans request.FILES['file'].

Notez que request.FILES ne contient les données que lorsque la méthode de requête est POST et que le formulaire``<form>`` à l’origine de la requête possède l’attribut enctype="multipart/form-data". Sinon, request.FILES est vide.

Most of the time, you’ll simply pass the file data from request into the form as described in Liaison de fichiers téléversés avec un formulaire. This would look something like:

views.py
Code
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm

# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

Remarquez que nous devons transmettre request.FILES au constructeur du formulaire ; c’est comme cela que les données de fichiers sont liées à un formulaire.

Voici une manière habituelle de gérer un fichier téléversé :

Code
def handle_uploaded_file(f):
    with open('some/file/name.txt', 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

En bouclant sur UploadedFile.chunks() au lieu d’appeler read(), on peut s’assurer que les gros fichiers ne saturent pas la mémoire du système.

Il existe quelques autres méthodes et attributs accessibles pour les objets UploadedFile. Voir UploadedFile pour une référence complète.

Téléversement de fichiers liés à un modèleLien vers cette rubrique

Si vous enregistrez un fichier dans un Model contenant un champ FileField, l’emploi d’un formulaire ModelForm simplifie le processus. L’objet fichier sera enregistré à l’emplacement indiqué par le paramètre upload_to du champ FileField correspondant lors de l’appel à form.save():

Code
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField

def upload_file(request):
    if request.method == 'POST':
        form = ModelFormWithFileField(request.POST, request.FILES)
        if form.is_valid():
            # file is saved
            form.save()
            return HttpResponseRedirect('/success/url/')
    else:
        form = ModelFormWithFileField()
    return render(request, 'upload.html', {'form': form})

Si vous construisez manuellement un objet, vous pouvez simplement attribuer l’objet fichier provenant de request.FILES au champ de fichier du modèle :

Code
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            instance = ModelWithFileField(file_field=request.FILES['file'])
            instance.save()
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

Uploading multiple filesLien vers cette rubrique

If you want to upload multiple files using one form field, set the multiple HTML attribute of field’s widget:

forms.py
Code
from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

Then override the post method of your FormView subclass to handle multiple file uploads:

views.py
Code
from django.views.generic.edit import FormView
from .forms import FileFieldForm

class FileFieldView(FormView):
    form_class = FileFieldForm
    template_name = 'upload.html'  # Replace with your template.
    success_url = '...'  # Replace with your URL or reverse().

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('file_field')
        if form.is_valid():
            for f in files:
                ...  # Do something with each file.
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

Gestionnaires de téléversementLien vers cette rubrique

Lorsqu’un utilisateur envoie un fichier, Django transmet les données du fichier à un gestionnaire de téléversement, une petite classe qui gère les données du fichier reçu. Les gestionnaires de téléversement sont définis initialement dans le réglage FILE_UPLOAD_HANDLERS dont le contenu par défaut est :

Code
["django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler"]

Conjointement, MemoryFileUploadHandler et TemporaryFileUploadHandler définissent le comportement Django par défaut de téléversement de fichier en plaçant les petits fichiers en mémoire et les plus gros sur le disque.

Vous pouvez écrire des gestionnaires personnalisée qui modifient la façon de gérer les fichiers. Vous pourriez par exemple utiliser des gestionnaires personnalisés pour limiter la quantité de données par utilisateur, compresser les données à la volée, afficher des barres de progression ou même envoyer directement des données vers un autre emplacement de stockage sans les stocker localement. Voir Écriture de gestionnaires de téléversement personnalisés pour plus de détails sur la manière de personnaliser ou de remplacer complètement le comportement de téléversement.

Emplacement de stockage des donnéesLien vers cette rubrique

Avant d’enregistrer des fichiers téléversés, les données doivent bien être stockées quelque part.

Par défaut, si un fichier téléversé est plus petit que 2,5 Mio, Django place la totalité du fichier en mémoire. Cela signifie que l’enregistrement du fichier correspond à une simple lecture en mémoire et à une écriture sur le disque, ce qui est très rapide.

Cependant, si un fichier téléversé est trop gros, Django écrit le fichier dans un fichier temporaire stocké dans le répertoire des fichiers temporaires du système. Sur une plate-forme de type Unix, Django va en principe générer un fichier dont le chemin correspond à quelque chose comme /tmp/tmpzfp6I6.upload. Si le fichier est suffisamment gros, vous pouvez même voir la taille du fichier augmenter au fur et à mesure de son flux d’enregistrement vers le disque.

Ces paramètres spécifiques, 2,5 Mio, /tmp, etc. ne sont que des valeurs par défaut « raisonnables » qui peuvent être personnalisés comme expliqué dans la section suivante.

Modification de la gestion des téléversementsLien vers cette rubrique

Certains réglages permettent de contrôler le comportement de téléversement de fichiers de Django. Voir Réglages de téléversement de fichiers pour plus de détails.

Modification des gestionnaires de téléversement à la voléeLien vers cette rubrique

Parfois, certaines vues ont besoin d’un comportement de téléversement différent. Dans ces situations, il est possible de surcharger les gestionnaires de téléversement par requête en modifiant request.upload_handlers. Par défaut, celle liste contient les gestionnaires de téléversement énumérés dans FILE_UPLOAD_HANDLERS, mais cette liste est modifiable comme n’importe quelle autre liste.

Par exemple, supposons que vous ayez écrit un gestionnaire ProgressBarUploadHandler qui renvoie des informations de progression de téléversement d’un composant AJAX quelconque. Voici comment ajouter ce gestionnaire à la liste des gestionnaires de téléversement :

Code
request.upload_handlers.insert(0, ProgressBarUploadHandler(request))

Dans ce cas, list.insert() peut être plus approprié que append() parce qu’un gestionnaire de barre de progression devrait être exécuté avant tout autre gestionnaire. Souvenez-vous que les gestionnaires de téléversement sont appelés dans l’ordre.

Si vous vouliez totalement remplacer les gestionnaires de téléversement, il suffirait d’attribuer une nouvelle liste :

Code
request.upload_handlers = [ProgressBarUploadHandler(request)]