Faits saillants de Django : se disputer les ressources statiques et les fichiers multimédias (partie 4)

Publié: 2022-03-10
Résumé rapide ↬ Les développeurs et les concepteurs frontaux créent des ressources statiques incroyables pour les applications Web. Aujourd'hui, nous nous concentrons sur ce qui se passe après que le correctif de style ou le beau graphique que vous venez de terminer est poussé à maîtriser. Nous étudierons également la gestion des fichiers que les utilisateurs téléchargent, appelés fichiers multimédias. Ensemble, nous développerons une intuition des stratégies disponibles pour les développeurs Django pour servir ces fichiers aux utilisateurs du monde entier de manière sécurisée, performante et rentable.

Les sites Web de Django impliquent beaucoup de fichiers. Il ne s'agit pas seulement de code source pour la configuration, les modèles, les vues et les templates, mais aussi d'actifs statiques : CSS et JavaScript, images, icônes. Comme si cela ne suffisait pas déjà, les utilisateurs arrivent parfois et souhaitent télécharger leurs propres fichiers sur votre site Web. C'est suffisant pour rendre n'importe quel développeur incrédule. Fichiers partout!

C'est là que j'aimerais pouvoir dire (sans avertissement) : "Ne vous inquiétez pas, Django vous soutient !" Mais malheureusement, lorsqu'il s'agit d'actifs statiques et de fichiers multimédias, il y a beaucoup de mises en garde à prendre en compte.

Aujourd'hui, nous aborderons le stockage et la diffusion de fichiers pour les déploiements à serveur unique et évolutifs tout en tenant compte de facteurs tels que la compression, la mise en cache et la disponibilité. Nous discuterons également des coûts et des avantages des CDN et des solutions de stockage de fichiers dédiées.

Remarque : Il ne s'agit pas d'un didacticiel expliquant comment déployer un site Django sur une plate-forme spécifique. Au lieu de cela, comme les autres articles de la série Django Highlights (voir ci-dessous), il est destiné à servir de guide aux développeurs et concepteurs frontaux pour comprendre d'autres parties du processus de création d'une application Web. Aujourd'hui, nous nous concentrons sur ce qui se passe après que le correctif de style ou le beau graphique que vous venez de terminer est poussé à maîtriser. Ensemble, nous développerons une intuition des stratégies disponibles pour les développeurs Django pour servir ces fichiers aux utilisateurs du monde entier de manière sécurisée, performante et rentable.

Pièces précédentes de la série :

  • Partie 1 : Modèles d'utilisateurs et authentification
  • Partie 2 : La création de modèles permet d'économiser des lignes
  • Partie 3 : Modèles, administration et exploitation de la base de données relationnelle
Plus après saut! Continuez à lire ci-dessous ↓

Définitions

La plupart de ces termes sont assez simples, mais cela vaut la peine de prendre un moment pour établir un vocabulaire commun pour cette discussion.

Les trois types de fichiers dans une application Django live sont :

  1. Code source
    Les fichiers Python et HTML créés avec le framework Django. Ces fichiers sont au cœur de l'application. Les fichiers de code source sont généralement assez petits, mesurés en kilo-octets.
  2. Fichiers statiques
    Également appelés « ressources statiques », ces fichiers incluent CSS et JavaScript, tous deux écrits par le développeur de l'application et des bibliothèques tierces, ainsi que des fichiers PDF, des programmes d'installation de logiciels, des images, de la musique, des vidéos et des icônes. Ces fichiers ne sont utilisés que côté client. Les fichiers statiques vont de quelques kilo-octets de CSS à des giga-octets de vidéo.
  3. Fichiers multimédias
    Tout fichier téléchargé par un utilisateur, des photos de profil aux documents personnels, est appelé un fichier multimédia. Ces fichiers doivent être stockés et récupérés de manière sécurisée et fiable pour l'utilisateur. Les fichiers multimédias peuvent être de n'importe quelle taille, l'utilisateur peut télécharger quelques kilo-octets de texte en clair sur quelques giga-octets de vidéo. Si vous êtes à la dernière extrémité de cette échelle, vous avez probablement besoin de conseils plus spécialisés que ce que cet article est prêt à donner.

Les deux types de déploiements Django sont :

  1. Serveur unique
    Un déploiement Django sur un seul serveur est exactement ce à quoi il ressemble : tout vit sur un seul serveur. Cette stratégie est très simple et ressemble étroitement à l'environnement de développement, mais ne peut pas gérer efficacement des volumes de trafic importants ou incohérents. L'approche à serveur unique ne s'applique qu'aux projets d'apprentissage ou de démonstration, et non aux applications de mots réels qui nécessitent une disponibilité fiable.
  2. Évolutif
    Il existe de nombreuses façons différentes de déployer un projet Django qui lui permet d'évoluer pour répondre à la demande des utilisateurs. Ces stratégies impliquent souvent de faire tourner de nombreux serveurs et d'utiliser des outils tels que des équilibreurs de charge et des bases de données gérées. Heureusement, nous pouvons effectivement regrouper tout ce qui est plus complexe qu'un déploiement sur un seul serveur dans cette catégorie aux fins de cet article.

Option 1 : Django par défaut

Les petits projets bénéficient d'une architecture simple. La gestion par défaut de Django des actifs statiques et des fichiers multimédias est juste cela : simple. Pour chacun, vous avez un dossier racine qui stocke les fichiers et vit juste à côté du code source sur le serveur. Simple. Ces dossiers racine sont générés et gérés principalement via la configuration yourproject/settings.py .

Actifs statiques

La chose la plus importante à comprendre lorsque vous travaillez avec des fichiers statiques dans Django est la commande python manage.py collectstatic . Cette commande parcourt le dossier statique de chaque application du projet Django et copie tous les actifs statiques dans le dossier racine. L'exécution de cette commande est une partie importante du déploiement d'un projet Django. Considérez la structure de répertoires suivante :

 - project - project - settings.py - urls.py - ... - app1 - static/ - app1 - style.css - script.js - img.jpg - templates/ - views.py - ... - app2 - static/ - app2 - style.css - image.png - templates/ - views.py - ...

Supposez également les paramètres suivants dans project/settings.py :

 STATIC_URL = "/static/" STATIC_ROOT = "/path/on/server/to/djangoproject/static"

L'exécution de la commande python manage.py collectstatic créera le dossier suivant sur le serveur :

 - /path/on/server/to/djangoproject/static - app1 - style.css - script.js - img.jpg - app2 - style.css - image.png

Notez que dans chaque dossier statique, il y a un autre dossier avec le nom de l'application. Cela permet d'éviter les conflits d'espace de noms après la collecte des fichiers statiques ; comme vous pouvez le voir dans la structure de fichier ci-dessus, cela permet de distinguer app1/style.css et app2/style.css . À partir de là, l'application recherchera des fichiers statiques dans cette structure à STATIC_ROOT pendant la production. En tant que tel, référencez les fichiers statiques comme suit dans un modèle dans app1/templates/ :

 {% load static %} <link rel="stylesheet" type="text/css" href="{% static "app1/style.css" %}">

Django détermine automatiquement où obtenir le fichier statique en développement pour modéliser ce comportement, vous n'avez pas besoin d'exécuter collectstatic pendant le développement.

Pour plus de détails, consultez la documentation de Django.

Fichiers multimédias

Imaginez un site de réseautage professionnel avec une base de données d'utilisateurs. Chacun de ces utilisateurs aurait un profil associé, qui pourrait contenir, entre autres, une image d'avatar et un document de CV. Voici un court exemple de modèle de ces informations :

 from django.db import models from django.contrib.auth.models import User def avatar_path(instance, filename): return "avatar_{}_{}".format(instance.user.id, filename) class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) resume = models.FileField(upload_to="path/string") avatar = models.ImageField(upload_to=avatar_path)

Pour que cela fonctionne, vous avez besoin des options suivantes dans project/settings.py , comme avec les ressources statiques :

 MEDIA_URL = "/media/" MEDIA_ROOT = "/path/on/server/to/media"

Un ImageField hérite de FileField , il partage donc les mêmes paramètres et fonctionnalités. Les deux champs ont un argument upload_to facultatif, qui prend une chaîne qui est un chemin et l'ajoute à MEDIA_ROOT pour stocker le fichier, qui est ensuite accessible par le même chemin au-dessus de MEDIA_URL . L'argument upload_to peut également prendre une fonction qui renvoie une chaîne, comme illustré avec la fonction avatar_path .

Assurez-vous d'omettre le répertoire des fichiers multimédias et son contenu du contrôle de version. Son contenu peut entrer en conflit lorsque deux développeurs testent la même application sur des machines différentes et, contrairement aux actifs statiques, il ne fait pas partie de l'application Django déployable.

Option 2 : Django avec services

Ma philosophie directrice est d'utiliser les outils pour ce qu'ils font de mieux. Django est un framework incroyable, et il fournit d'excellents outils prêts à l'emploi pour l'authentification des utilisateurs, le rendu côté serveur, l'utilisation de modèles et de formulaires, les fonctions administratives et des dizaines d'autres aspects essentiels de la création d'applications Web. Cependant, ses outils de gestion des ressources statiques et des fichiers multimédias ne sont pas, à mon avis, bien adaptés à la production sur des sites évolutifs. Les développeurs principaux de Django reconnaissent que de nombreuses personnes choisissent des approches alternatives pour gérer ces fichiers en production ; le cadre est très bon pour sortir de votre chemin quand vous le faites. La plupart des sites Django destinés à un usage général voudront incorporer des actifs statiques et gérer des fichiers multimédias en utilisant ces approches non spécifiques à Django.

Actifs statiques sur un CDN

Alors que les petits et moyens projets peuvent s'en passer, un CDN (réseau de diffusion de contenu) est facile à utiliser et améliore les performances des applications de toute taille. Un CDN est un réseau de serveurs, généralement dans le monde entier, qui distribue et sert du contenu Web, principalement des actifs statiques. Les CDN populaires incluent Cloudflare CDN, Amazon CloudFront et Fastly. Pour utiliser un CDN, vous uploadez vos fichiers statiques, puis dans votre application référencez-les comme suit :

 <link rel="stylesheet" type="text/css" href="https://cdn.example.com/path/to/your/files/app1/style.css">

Ce processus est facile à intégrer à vos scripts de déploiement Django. Après avoir exécuté la commande python manage.py collectstatic , copiez le répertoire généré sur votre CDN (un processus qui varie considérablement en fonction du service que vous utilisez), puis supprimez les ressources statiques du package de déploiement Django.

En développement, vous souhaiterez accéder à différentes copies de vos actifs statiques par rapport à la production. De cette façon, vous pouvez apporter des modifications localement sans affecter le site de production. Vous pouvez soit utiliser des actifs locaux, soit exécuter une deuxième instance du CDN pour livrer les fichiers. Configurez yourproject/settings.py avec une variable personnalisée, comme CDN_URL , et utilisez cette valeur dans vos modèles pour vous assurer que vous utilisez la bonne version des ressources en développement et en production.

Une dernière note est que de nombreuses bibliothèques pour CSS et JavaScript ont des CDN gratuits que la plupart des sites Web peuvent utiliser. Si vous chargez, par exemple, Bootstrap 4 ou underscore.js, vous pouvez éviter les tracas liés à l'utilisation de votre propre copie en développement et les dépenses liées au service de vos propres copies en production en utilisant ces CDN publics.

Fichiers multimédias avec un magasin de fichiers dédié

Aucun site Django de production ne doit stocker les fichiers utilisateur dans un simple dossier /media/ quelque part sur le serveur qui exécute le site. Voici trois des nombreuses raisons de ne pas le faire :

  1. Si vous devez faire évoluer le site en ajoutant plusieurs serveurs, vous avez besoin d'un moyen de copier et de synchroniser les fichiers téléchargés sur ces serveurs.
  2. Si un serveur tombe en panne, le code source est sauvegardé dans votre système de contrôle de version, mais les fichiers multimédias ne sont pas sauvegardés par défaut, sauf si vous avez configuré votre serveur pour le faire, mais pour cet effort, vous feriez mieux d'utiliser un serveur dédié magasin de fichiers.
  3. En cas d'activité malveillante, il est quelque peu préférable de conserver les fichiers téléchargés par l'utilisateur sur un serveur distinct de celui qui exécute l'application, bien que cela ne supprime en rien l'obligation de valider les fichiers téléchargés par l'utilisateur.

L'intégration d'un tiers pour stocker vos fichiers téléchargés par l'utilisateur est vraiment facile. Vous n'avez pas besoin de changer quoi que ce soit dans votre code, sauf peut-être de supprimer ou de modifier la valeur upload_to de FileField s dans vos modèles et de configurer quelques paramètres. Par exemple, si vous envisagez de stocker vos fichiers dans AWS S3, vous souhaiterez procéder comme suit, ce qui est très similaire au processus de stockage de fichiers avec Google Cloud, Azure, Backblaze ou des services concurrents similaires.

Tout d'abord, vous devrez installer les bibliothèques boto3 et django-storages . Ensuite, vous devez configurer un compartiment et un rôle IAM sur AWS, ce qui n'entre pas dans le cadre de cet article, mais vous pouvez voir les instructions ici. Une fois tout cela configuré, vous devez ajouter trois variables à votre project/settings.py :

 DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" AWS_STORAGE_BUCKET_NAME = "BUCKET_NAME" AWS_S3_REGION_NAME = "us-east-2"

De plus, vous devrez configurer l'accès des informations d'identification à votre compartiment AWS. Certains didacticiels illustreront l'ajout d'un ID et d'une clé secrète à votre fichier de paramètres ou en tant que variables d'environnement, mais ce sont des pratiques non sécurisées. Utilisez django-storages avec l'AWS CLI pour configurer les clés, comme décrit ici. Vous pouvez également être intéressé par la documentation django-storages .

Vous ne voulez pas que les fichiers multimédias de développement ou de test soient mélangés avec les téléchargements des utilisateurs réels. Éviter cela est assez simple : configurez plusieurs compartiments, un pour le développement (ou un pour chaque développeur), un pour les tests et un pour la production. Ensuite, tout ce que vous devez modifier est le paramètre AWS_STORAGE_BUCKET_NAME par environnement et vous êtes prêt à partir.

Performances et disponibilité

De nombreux facteurs affectent les performances et la fiabilité de votre site Web. Voici quelques éléments importants lorsque vous envisagez des fichiers statiques et multimédias qui comptent, quelle que soit l'approche que vous adoptez pour les gérer.

Coût

Servir des fichiers à un utilisateur coûte de l'argent pour deux raisons : le stockage et la bande passante. Vous devez payer le fournisseur d'hébergement pour qu'il stocke les fichiers pour vous, mais vous devez également le payer pour qu'il serve les fichiers. La bande passante est nettement plus chère que le stockage (par exemple, AWS S3 facture 2,3 cents par gigaoctet pour le stockage contre 9 cents par gigaoctet de transfert de données vers Internet au moment de la rédaction). L'économie d'un magasin de fichiers comme S3 ou d'un CDN est différente de celle d'un hôte généralisé comme une gouttelette Digital Ocean. Profitez de la spécialisation et des économies d'échelle en transférant des fichiers coûteux vers des services conçus pour eux. De plus, de nombreux magasins de fichiers et CDN proposent des plans gratuits afin que les sites qui pourraient être suffisamment petits pour s'en sortir sans les utiliser puissent le faire à la place et en récolter les bénéfices sans aucun coût d'infrastructure supplémentaire.

Compression et transcodage

La plupart des problèmes causés par les ressources statiques telles que les photos et les vidéos sont dus au fait qu'il s'agit de fichiers volumineux. Naturellement, les développeurs résolvent ce problème en essayant de réduire la taille de ces fichiers. Il existe plusieurs façons de le faire en utilisant un mélange de compression et de transcodage dans deux catégories générales : sans perte et avec perte. La compression sans perte conserve la qualité d'origine des actifs, mais offre des diminutions relativement modestes de la taille des fichiers. La compression avec perte, ou le transcodage dans un format avec perte, permet des tailles de fichiers beaucoup plus petites au détriment de la perte d'une partie de la qualité de l'artefact d'origine. Un exemple de ceci est le transcodage vidéo à un débit binaire inférieur. Pour plus de détails, consultez cet article sur l'optimisation de la diffusion vidéo. Lors de la diffusion de fichiers volumineux sur le Web, les vitesses de bande passante exigent souvent que vous serviez des artefacts hautement compressés, ce qui nécessite une compression avec perte.

Sauf si vous êtes YouTube, la compression et le transcodage ne se font pas à la volée. Les actifs statiques doivent être formatés de manière appropriée avant le déploiement, et vous pouvez appliquer des restrictions de base sur le type de fichier et la taille de fichier sur les téléchargements d'utilisateurs pour garantir une compression suffisante et un formatage approprié dans les fichiers multimédias de vos utilisateurs.

Minification

Bien que les fichiers JavaScript et CSS ne soient généralement pas aussi volumineux que les images, ils peuvent souvent être compressés pour réduire le nombre d'octets. Ce processus est appelé minification. La minification ne change pas l'encodage des fichiers, ils sont toujours du texte, et un fichier minifié doit toujours être un code valide pour sa langue d'origine. Les fichiers minifiés conservent leurs extensions d'origine.

La principale chose supprimée dans un fichier minifié est l'espace blanc inutile, et du point de vue de l'ordinateur, presque tous les espaces blancs en CSS et JavaScript sont inutiles. Les schémas de minification raccourcissent également les noms de variables et suppriment les commentaires.

La minification par défaut obscurcit le code ; en tant que développeur, vous devez travailler exclusivement avec des fichiers non minifiés. Certaines étapes automatiques au cours du processus de déploiement devraient réduire les fichiers avant qu'ils ne soient stockés et servis. Si vous utilisez une bibliothèque fournie par un CDN tiers, assurez-vous d'utiliser la version réduite de cette bibliothèque si elle est disponible. Les fichiers HTML peuvent être minifiés, mais comme Django utilise le rendu côté serveur, le coût de traitement à la volée compenserait très probablement la petite diminution de la taille de la page.

Disponibilité mondiale

Tout comme il faut moins de temps pour envoyer une lettre à votre voisin que pour l'envoyer à travers le pays, il faut moins de temps pour transmettre des données à proximité qu'à travers le monde. L'un des moyens par lesquels un CDN améliore les performances des pages consiste à copier des ressources sur des serveurs du monde entier. Ensuite, lorsqu'un client fait une demande, il reçoit les actifs statiques du serveur le plus proche (souvent appelé nœud périphérique), ce qui réduit les temps de chargement. L'un des avantages d'utiliser un CDN avec un site Django est de découpler la distribution globale de vos assets statiques de la distribution globale de votre code.

Mise en cache côté client

Quoi de mieux que d'avoir un fichier statique sur un serveur proche de votre utilisateur ? Avoir le fichier statique déjà stocké sur l'appareil de votre utilisateur ! La mise en cache est le processus de stockage des résultats d'un calcul ou d'une requête afin qu'ils puissent être consultés à plusieurs reprises plus rapidement. Tout comme une feuille de style CSS peut être mise en cache dans le monde entier dans un CDN, elle peut être mise en cache dans le navigateur du client la première fois qu'il charge une page de votre site. Ensuite, la feuille de style est disponible sur l'appareil lui-même dans les requêtes suivantes, de sorte que le client effectue moins de requêtes, améliore le temps de chargement des pages et diminue l'utilisation de la bande passante.

Les navigateurs effectuent leurs propres opérations de mise en cache, mais si votre site bénéficie d'un trafic important, vous pouvez optimiser votre comportement de mise en cache côté client à l'aide du framework de cache de Django.

En conclusion

Encore une fois, ma philosophie directrice est d'utiliser les outils pour ce qu'ils font de mieux. Les projets à serveur unique et les petits déploiements évolutifs avec uniquement des actifs statiques légers peuvent utiliser la gestion intégrée des actifs statiques de Django, mais la plupart des applications doivent séparer les actifs à servir sur un CDN.

Si votre projet est destiné à tout type d'utilisation de mots réels, ne stockez pas les fichiers multimédias avec la méthode par défaut de Django, utilisez plutôt un service. Avec suffisamment de trafic, où "assez de trafic" est un nombre relativement petit à l'échelle d'Internet, les complications supplémentaires de l'architecture, du processus de développement et du déploiement en valent la peine pour les performances, la fiabilité et les économies de coûts d'utilisation d'un CDN et solution de stockage de fichiers distincts pour les fichiers statiques et multimédias, respectivement.

lecture recommandée

  • Partie 1 : Modèles d'utilisateurs et authentification
  • Partie 2 : La création de modèles permet d'économiser des lignes
  • Partie 3 : Modèles, administration et exploitation de la base de données relationnelle