# Documentation Django 5.2.8

# Gestion des fichiers

Ce document décrit l’API Django d’accès aux fichiers adaptée par exemple aux fichiers envoyés par les utilisateurs. Les API de plus bas niveau sont assez générales pour pouvoir être utilisées dans d’autres buts. Si vous souhaitez gérer les « fichiers statiques » (JS, CSS, etc.), consultez Gestion des fichiers statiques (par ex. images, JavaScript, CSS).

Par défaut, Django stocke les fichiers localement, en fonction des réglages `MEDIA_ROOT` et `MEDIA_URL`. Les exemples ci-dessous partent du principe que vous utilisez ces valeurs par défaut.

Cependant, Django permet d’écrire des systèmes de stockage de fichiers spécialisés permettant de personnaliser complètement l’endroit et la façon dont Django stocke les fichiers. La deuxième partie de ce document décrit le fonctionnement des ces systèmes de stockage.

## Utilisation des fichiers dans les modèles

Quand vous utilisez un `FileField` ou un `ImageField`, Django fournit un ensemble d’API pour pouvoir manipuler le fichier correspondant.

Considérez le modèle suivant qui utilise un `ImageField` pour stocker une photo :

    from django.db import models

    class Car(models.Model):
        name = models.CharField(max_length=255)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        photo = models.ImageField(upload_to="cars")
        specs = models.FileField(upload_to="specs")

Toute instance de `Car` possède un attribut `photo` qu’il est possible d’utiliser pour obtenir les détails de la photo jointe :

    >>> car = Car.objects.get(name="57 Chevy")
    >>> car.photo
    <ImageFieldFile: cars/chevy.jpg>
    >>> car.photo.name
    'cars/chevy.jpg'
    >>> car.photo.path
    '/media/cars/chevy.jpg'
    >>> car.photo.url
    'https://media.example.com/cars/chevy.jpg'

Cet objet (`car.photo` dans l’exemple) est un objet `File`, ce qui signifie qu’il possède toutes les méthodes et les attributs documentés ci-dessous.

Note

Le fichier est enregistré durant la phase d’enregistrement du modèle dans la base de données, il n’est donc pas possible de se baser sur le nom de fichier réel sur le disque tant que le modèle lui-même n’a pas été enregistré.

Par exemple, vous pouvez modifier le nom de fichier en définissant l’attribut `name` du fichier à un chemin relatif à l’emplacement de stockage des fichiers (`MEDIA_ROOT` si vous utilisez le `FileSystemStorage` par défaut) :

    >>> import os
    >>> from django.conf import settings
    >>> initial_path = car.photo.path
    >>> car.photo.name = "cars/chevy_ii.jpg"
    >>> new_path = os.path.join(settings.MEDIA_ROOT, car.photo.name)
    >>> # Move the file on the filesystem
    >>> os.rename(initial_path, new_path)
    >>> car.save()
    >>> car.photo.path
    '/media/cars/chevy_ii.jpg'
    >>> car.photo.path == new_path
    True

Pour enregistrer un fichier existant sur le disque dans un champ `FileField`:

    >>> from pathlib import Path
    >>> from django.core.files import File
    >>> path = Path("/some/external/specs.pdf")
    >>> car = Car.objects.get(name="57 Chevy")
    >>> with path.open(mode="rb") as f:
    ...     car.specs = File(f, name=path.name)
    ...     car.save()
    ...

Note

Bien que les attributs de données « non image » du champ `ImageField`, tels que `height`, `width` et `size` (hauteur, largeur et taille), sont disponibles sur l’instance, les données d’image sous-jacente ne peuvent pas être utilisées sans réouvrir l’image. Par exemple :

    >>> from PIL import Image
    >>> car = Car.objects.get(name="57 Chevy")
    >>> car.photo.width
    191
    >>> car.photo.height
    287
    >>> image = Image.open(car.photo)
    # Raises ValueError: seek of closed file.
    >>> car.photo.open()
    <ImageFieldFile: cars/chevy.jpg>
    >>> image = Image.open(car.photo)
    >>> image
    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=191x287 at 0x7F99A94E9048>

## L’objet

En interne, Django utilise une instance de `django.core.files.File` chaque fois qu’il a besoin de représenter un fichier.

La plupart du temps, vous utiliserez l’objet `File` que Django vous transmet (par exemple un fichier joint à un modèle comme ci-dessus ou peut-être un fichier téléversé).

Si vous avez besoin de construire vous-même un objet `File`, la façon la plus simple est de le créer en utilisant un objet `file` de Python :

    >>> from django.core.files import File

    # Create a Python file object using open()
    >>> f = open("/path/to/hello.world", "w")
    >>> myfile = File(f)

Il est maintenant possible d’utiliser les attributs et les méthodes documentés de la classe `File`.

Il faut savoir que les fichiers créés de cette façon ne sont pas fermés automatiquement. L’approche suivante peut être employée pour fermer automatiquement les fichiers :

    >>> from django.core.files import File

    # Create a Python file object using open() and the with statement
    >>> with open("/path/to/hello.world", "w") as f:
    ...     myfile = File(f)
    ...     myfile.write("Hello World")
    ...
    >>> myfile.closed
    True
    >>> f.closed
    True

La fermeture des fichiers est particulièrement importante lors de l’accès en boucle à des champs fichier pour un grand nombre d’objets. Si les fichiers ne sont pas fermés manuellement après les avoir lus, il y a un risque d’épuisement des descripteurs de fichiers. Cela peut amener à l’erreur suivante :

    OSError: [Errno 24] Too many open files

## Stockage des fichiers

En arrière-plan, Django délègue les décisions au sujet des emplacements des fichiers et de la manière de les stocker à un système de stockage de fichiers. C’est cet objet qui s’occupe réellement des systèmes de fichiers, de l’ouverture et de la lecture des fichiers, etc.

Le stockage de fichiers par défaut de Django est `'``django.core.files.storage.FileSystemStorage``'`. Si vous n’indiquez pas explicitement un système de stockage dans la clé `default` du réglage `STORAGES`, c’est celui qui sera utilisé.

Lisez ci-dessous pour obtenir des détails sur le système de stockage de fichiers intégré par défaut et lisez Écriture d’une classe de stockage personnalisée pour plus d’informations sur l’écriture de son propre système de stockage de fichiers.

### Objets de stockage

Bien que la plupart du temps il soit plus opportun de manipuler un objet `File` (qui délègue au stockage adapté pour ce fichier), il est possible d’utiliser directement un stockage de fichiers. Vous pouvez créer une instance d’une classe de stockage de fichiers personnalisé ou, plus souvent utile, vous pouvez utiliser le système de stockage global par défaut :

    >>> from django.core.files.base import ContentFile
    >>> from django.core.files.storage import default_storage

    >>> path = default_storage.save("path/to/file", ContentFile(b"new content"))
    >>> path
    'path/to/file'

    >>> default_storage.size(path)
    11
    >>> default_storage.open(path).read()
    b'new content'

    >>> default_storage.delete(path)
    >>> default_storage.exists(path)
    False

Voir API de stockage des fichiers concernant l’API de stockage de fichiers.

### La classe de Django pour le stockage sur système de fichiers

Django fournit une classe `django.core.files.storage.FileSystemStorage` qui implémente les éléments de base du stockage de fichiers sur un système de fichiers.

Par exemple, le code suivant stocke les fichiers téléversés dans `/media/photos` quelle que soit la valeur du réglage `MEDIA_ROOT`:

    from django.core.files.storage import FileSystemStorage
    from django.db import models

    fs = FileSystemStorage(location="/media/photos")

    class Car(models.Model):
        ...
        photo = models.ImageField(storage=fs)

Les systèmes de stockage personnalisés fonctionnent de la même manière : vous pouvez les transmettre comme paramètre `storage` d’un champ `FileField`.

### Utilisation d’un exécutable

Vous pouvez transmettre un objet exécutable comme paramètre `storage` de `FileField` ou de `ImageField`. Cela permet de modifier le stockage utilisé au moment de l’exécution, choisissant par exemple différents stockages en fonction de l’environnement.

L’exécutable sera évalué au moment où les classes de modèles sont chargées et doit renvoyer une instance de `Storage`.

Par exemple :

    from django.conf import settings
    from django.db import models
    from .storages import MyLocalStorage, MyRemoteStorage

    def select_storage():
        return MyLocalStorage() if settings.DEBUG else MyRemoteStorage()

    class MyModel(models.Model):
        my_file = models.FileField(storage=select_storage)

Afin de définir un stockage défini dans le réglage `STORAGES`, vous pouvez utiliser `storages`:

    from django.core.files.storage import storages

    def select_storage():
        return storages["mystorage"]

    class MyModel(models.Model):
        upload = models.FileField(storage=select_storage)

Comme l’exécutable est évalué au moment où les classes de modèles sont chargées, si vous devez surcharger le réglage `STORAGES` dans les tests, vous devriez utiliser une sous-classe `LazyObject` à la place :

    from django.core.files.storage import storages
    from django.utils.functional import LazyObject

    class OtherStorage(LazyObject):
        def _setup(self):
            self._wrapped = storages["mystorage"]

    my_storage = OtherStorage()

    class MyModel(models.Model):
        upload = models.FileField(storage=my_storage)

L’objet `LazyObject` diffère l’évaluation du stockage jusqu’au moment où il est réellement employé, ce qui permet à `override_settings()` de faire effet :

    @override_settings(
        STORAGES={
            "mystorage": {
                "BACKEND": "django.core.files.storage.InMemoryStorage",
            }
        }
    )
    def test_storage():
        model = MyModel()
        assert isinstance(model.upload.storage, InMemoryStorage)