• en
  • Langue : fr

Écriture d’un système de stockage personnalisé

Si vous avez besoin de fournir un stockage de fichiers personnalisé, typiquement pour stocker des fichiers dans un système distant, vous pouvez le faire en définissant une classe de stockage personnalisée. Il faudra suivre ces étapes :

  1. Votre système de stockage personnalisé doit être une sous-classe de django.core.files.storage.Storage:

    from django.core.files.storage import Storage
    
    class MyStorage(Storage):
        ...
    
  2. Django doit être capable d’instancier votre système de stockage sans paramètre. Cela signifie que tout réglage doit provenir de django.conf.settings:

    from django.conf import settings
    from django.core.files.storage import Storage
    
    class MyStorage(Storage):
        def __init__(self, option=None):
            if not option:
                option = settings.CUSTOM_STORAGE_OPTIONS
            ...
    
  3. Votre classe de stockage doit implémenter les méthodes _open() et _save(), en plus de toute autre méthode adéquate pour votre classe de stockage. Voir ci-dessous pour plus de détails sur ces méthodes.

    De plus, si votre classe propose du stockage de fichiers locaux, elle doit surcharger la méthode path().

  4. Votre classe de stockage doit être déconstructible pour pouvoir être sérialisée lorsqu’elle est référencée dans un champ dans une migration. Tant que les paramètres du champ sont eux-mêmes sérialisables, vous pouvez utiliser le décorateur de classe django.utils.deconstruct.deconstructible pour cela (c’est ce que Django utilise pour FileSystemStorage).

Par défaut, les méthodes suivantes génèrent NotImplementedError et doivent typiquement être surchargées :

Notez cependant que ces méthodes ne sont pas toutes obligatoires et peuvent être délibérément omises. Il est même possible d’obtenir une classe de stockage fonctionnelle sans implémenter aucune de ces méthodes.

À titre d’exemple, si l’énumération du contenu de certains moteurs de stockage se révèle coûteuse, il est tout à fait possible de décider de ne pas implémenter Storage.listdir.

Un autre exemple pourrait être un moteur qui ne gère que l’écriture dans des fichiers. Dans ce cas, il ne serait pas nécessaire d’implémenter une seule des méthodes ci-dessus.

Au final, le choix des méthodes à implémenter vous revient. En laissant certaines méthodes non implémentées, l’interface proposée sera partielle (voire défectueuse).

Il est généralement souhaitable d’implémenter les méthodes tout spécialement conçues pour les objets de stockage personnalisé. Ce sont :

_open(name, mode='rb')

Obligatoire.

Appelée par Storage.open(), c’est le mécanisme utilisé par la classe de stockage pour ouvrir un fichier. Elle doit renvoyer un objet File, même si dans la plupart des cas, elle renverra plutôt une sous-classe qui implémente la logique particulière du moteur de stockage.

_save(name, content)

Appelée par Storage.save(). Le paramètre name aura déjà passé par get_valid_name() et get_available_name(), et content sera un objet de type File.

Elle doit renvoyer le nom réel du fichier enregistré (normalement le paramètre name, mais si le stockage a besoin de modifier le nom de fichier, c’est le nouveau nom qui devra être renvoyé).

get_valid_name(name)

Renvoie un nom de fichier acceptable par le système de stockage sous-jacent. Le paramètre name passé à cette méthode est le nom de fichier original envoyé au serveur, dépourvu de toute notion de chemin. Surchargez cette méthode pour personnaliser la manière dont des caractères non standards sont convertis pour former des noms de fichiers sûrs.

Le code fourni par Storage ne conserve que les caractères alphanumériques, les points et les soulignements du nom de fichier original, supprimant tout le reste.

get_available_name(name, max_length=None)

Renvoie un nom de fichier disponible (non existant) dans le mécanisme de stockage, prenant potentiellement en compte le nom de fichier fourni. Le paramètre name transmis à cette méthode aura déjà été nettoyé afin d’être un nom de fichier valable pour le système de stockage, en accord avec la méthode get_valid_name() décrite ci-dessus.

La longueur du nom de fichier ne dépassera pas max_length, si cette option est indiquée. Si un nom de fichier unique n’est pas disponible, une exception SuspiciousFileOperation est générée.

Si un fichier avec name existe déjà, un soulignement suivi d’une chaîne aléatoire de 7 caractères alphanumériques est ajouté à la fin du nom du fichier avant l’extension.

Changed in Django 1.7:

Précédemment, un underscore et un numbre (par exemple "_1", "_2", etc.) étaient ajoutés à la fin du nom de fichier jusqu’à ce qu’un nom soit disponible dans le répertoire de destination. Un utilisateur malveillant pouvait exploiter cet algorithme déterministe pour mener à bien une attaque de type denial-of-service. Cette modification a également été effectuée dans les versions 1.6.6, 1.5.9 et 1.4.14 de Django.

Changed in Django 1.8:

Le paramètre max_length a été ajouté.

Back to Top