Django-Highlights: Umgang mit statischen Assets und Mediendateien (Teil 4)

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Front-End-Entwickler und -Designer erstellen erstaunliche statische Assets für Webanwendungen. Heute konzentrieren wir uns darauf, was passiert, nachdem der Stil-Hotfix oder die schöne Grafik, die Sie gerade fertiggestellt haben, zum Meistern gepusht wird. Wir untersuchen auch den Umgang mit Dateien, die von Benutzern hochgeladen werden, sogenannten Mediendateien. Gemeinsam entwickeln wir ein Gespür für die Strategien, die Django-Entwicklern zur Verfügung stehen, um diese Dateien Benutzern weltweit auf sichere, leistungsfähige und kostengünstige Weise bereitzustellen.

Django-Websites beinhalten viele Dateien. Es ist nicht nur Quellcode für die Konfiguration, Modelle, Ansichten und Vorlagen, sondern auch statische Assets: CSS und JavaScript, Bilder, Symbole. Als ob das nicht schon genug wäre, kommen manchmal Benutzer vorbei und wollen ihre eigenen Dateien auf Ihre Website hochladen. Es ist genug, um jeden Entwickler ungläubig zu machen. Dateien überall!

Hier wünschte ich, ich könnte sagen (ohne Vorbehalte): „Keine Sorge, Django steht hinter dir!“ Aber leider gibt es beim Umgang mit statischen Assets und Mediendateien viele Vorbehalte zu beachten.

Heute befassen wir uns mit dem Speichern und Bereitstellen von Dateien sowohl für Einzelserver- als auch für skalierbare Bereitstellungen unter Berücksichtigung von Faktoren wie Komprimierung, Caching und Verfügbarkeit. Wir werden auch die Kosten und Vorteile von CDNs und dedizierten Dateispeicherlösungen besprechen.

Hinweis : Dies ist kein Tutorial zum Bereitstellen einer Django-Site auf einer bestimmten Plattform. Stattdessen ist es wie die anderen Artikel in der Reihe „Django Highlights“ (siehe unten) als Leitfaden für Front-End-Entwickler und -Designer gedacht, um andere Teile des Prozesses zum Erstellen einer Webanwendung zu verstehen. Heute konzentrieren wir uns darauf, was passiert, nachdem der Stil-Hotfix oder die schöne Grafik, die Sie gerade fertiggestellt haben, zum Meistern gepusht wird. Gemeinsam entwickeln wir ein Gespür für die Strategien, die Django-Entwicklern zur Verfügung stehen, um diese Dateien Benutzern weltweit auf sichere, leistungsfähige und kostengünstige Weise bereitzustellen.

Vorherige Teile der Serie:

  • Teil 1: Benutzermodelle und Authentifizierung
  • Teil 2: Templating spart Zeilen
  • Teil 3: Modelle, Verwaltung und Nutzung der relationalen Datenbank
Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Definitionen

Die meisten dieser Begriffe sind ziemlich einfach, aber es lohnt sich, sich einen Moment Zeit zu nehmen, um ein gemeinsames Vokabular für diese Diskussion zu erstellen.

Die drei Arten von Dateien in einer Live-Django-Anwendung sind:

  1. Quellcode
    Die Python- und HTML-Dateien, die mit dem Django-Framework erstellt werden. Diese Dateien sind der Kern der Anwendung. Quellcodedateien sind im Allgemeinen ziemlich klein, gemessen in Kilobyte.
  2. Statische Dateien
    Diese Dateien werden auch als „statische Assets“ bezeichnet und umfassen CSS und JavaScript, die beide vom Anwendungsentwickler und Bibliotheken von Drittanbietern geschrieben wurden, sowie PDFs, Software-Installationsprogramme, Bilder, Musik, Videos und Symbole. Diese Dateien werden nur clientseitig verwendet. Statische Dateien reichen von wenigen Kilobyte CSS bis hin zu Gigabyte Video.
  3. Media-Dateien
    Jede von einem Benutzer hochgeladene Datei, von Profilbildern bis hin zu persönlichen Dokumenten, wird als Mediendatei bezeichnet. Diese Dateien müssen für den Benutzer sicher und zuverlässig gespeichert und abgerufen werden. Mediendateien können beliebig groß sein, der Benutzer kann ein paar Kilobyte Klartext auf ein paar Gigabyte Video hochladen. Wenn Sie sich am letzten Ende dieser Skala befinden, benötigen Sie wahrscheinlich spezialisiertere Ratschläge, als dieser Artikel bereit ist zu geben.

Die zwei Arten von Django-Bereitstellungen sind:

  1. Single-Server
    Eine Single-Server-Django-Bereitstellung ist genau das, wonach es sich anhört: Alles lebt auf einem einzigen Server. Diese Strategie ist sehr einfach und ähnelt stark der Entwicklungsumgebung, kann jedoch große oder inkonsistente Mengen an Datenverkehr nicht effektiv bewältigen. Der Single-Server-Ansatz ist nur für Lern- oder Demonstrationsprojekte anwendbar, nicht für reale Anwendungen, die eine zuverlässige Betriebszeit erfordern.
  2. Skalierbar
    Es gibt viele verschiedene Möglichkeiten, ein Django-Projekt bereitzustellen, mit dem es skaliert werden kann, um die Benutzeranforderungen zu erfüllen. Diese Strategien beinhalten oft das Hoch- und Herunterfahren zahlreicher Server und den Einsatz von Tools wie Load Balancern und verwalteten Datenbanken. Glücklicherweise können wir für die Zwecke dieses Artikels effektiv alles, was komplexer ist als eine Bereitstellung auf einem einzigen Server, in diese Kategorie einordnen.

Option 1: Standard-Django

Kleine Projekte profitieren von einfacher Architektur. Djangos standardmäßiger Umgang mit statischen Assets und Mediendateien ist genau das: einfach. Für jeden haben Sie einen Stammordner, der die Dateien speichert und direkt neben dem Quellcode auf dem Server liegt. Einfach. Diese Stammordner werden hauptsächlich über die Konfiguration yourproject/settings.py generiert und verwaltet.

Statische Assets

Das Wichtigste, was Sie beim Arbeiten mit statischen Dateien in Django verstehen müssen, ist der Befehl python manage.py collectstatic . Dieser Befehl durchsucht den statischen Ordner jeder App im Django-Projekt und kopiert alle statischen Assets in den Stammordner. Das Ausführen dieses Befehls ist ein wichtiger Teil der Bereitstellung eines Django-Projekts. Betrachten Sie die folgende Verzeichnisstruktur:

 - 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 - ...

Nehmen Sie auch die folgenden Einstellungen in project/settings.py an:

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

Durch Ausführen des python manage.py collectstatic wird der folgende Ordner auf dem Server erstellt:

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

Beachten Sie, dass sich in jedem statischen Ordner ein weiterer Ordner mit dem Namen der App befindet. Dies dient dazu, Namespace-Konflikte zu verhindern, nachdem die statischen Dateien gesammelt wurden; Wie Sie in der obigen Dateistruktur sehen können, bleiben app1/style.css und app2/style.css getrennt. Von hier aus sucht die Anwendung während der Produktion nach statischen Dateien in dieser Struktur im STATIC_ROOT . Verweisen Sie daher auf statische Dateien wie folgt in einer Vorlage in app1/templates/ :

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

Django findet automatisch heraus, woher die statische Datei in der Entwicklung kommt, um dieses Verhalten zu modellieren, Sie müssen collectstatic während der Entwicklung nicht ausführen.

Weitere Einzelheiten finden Sie in der Django-Dokumentation.

Media-Dateien

Stellen Sie sich eine professionelle Networking-Site mit einer Datenbank von Benutzern vor. Jeder dieser Benutzer hätte ein zugeordnetes Profil, das unter anderem ein Avatarbild und ein Lebenslaufdokument enthalten könnte. Hier ist ein kurzes Beispielmodell dieser Informationen:

 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)

Damit dies funktioniert, benötigen Sie wie bei statischen Assets die folgenden Optionen in project/settings.py :

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

Ein ImageField erbt von FileField , sodass es dieselben Parameter und Funktionen teilt. Beide Felder haben ein optionales upload_to -Argument, das eine Zeichenfolge, die ein Pfad ist, nimmt und an MEDIA_ROOT , um die Datei zu speichern, auf die dann über denselben Pfad über MEDIA_URL . Das upload_to Argument kann auch eine Funktion annehmen, die einen String zurückgibt, wie mit der avatar_path Funktion demonstriert.

Stellen Sie sicher, dass Sie das Mediendateiverzeichnis und seinen Inhalt aus der Versionskontrolle ausschließen. Ihr Inhalt kann widersprüchlich sein, wenn zwei Entwickler dieselbe Anwendung auf verschiedenen Computern testen, und sie ist im Gegensatz zu statischen Assets kein Teil der bereitstellbaren Django-Anwendung.

Option 2: Django mit Diensten

Meine Leitphilosophie ist es, Werkzeuge für das einzusetzen, was sie am besten können. Django ist ein erstaunliches Framework und bietet großartige Tools für die Benutzerauthentifizierung, das serverseitige Rendern, das Arbeiten mit Modellen und Formularen, Verwaltungsfunktionen und Dutzende anderer wesentlicher Aspekte beim Erstellen von Webanwendungen. Allerdings sind die Tools zum Umgang mit statischen Assets und Mediendateien meiner Meinung nach nicht gut für die Produktion auf skalierbaren Websites geeignet. Die Django-Core-Entwickler erkennen, dass viele Leute alternative Ansätze für den Umgang mit diesen Dateien in der Produktion wählen; Das Framework ist sehr gut darin, Ihnen aus dem Weg zu gehen, wenn Sie dies tun. Die meisten Django-Sites, die für den allgemeinen Gebrauch bestimmt sind, möchten statische Assets integrieren und Mediendateien mit diesen nicht Django-spezifischen Ansätzen handhaben.

Statische Assets auf einem CDN

Während kleine bis mittlere Projekte ohne eines auskommen können, ist ein CDN (Content Delivery Network) einfach zu verwenden und verbessert die Leistung von Anwendungen jeder Größe. Ein CDN ist ein Netzwerk von Servern, im Allgemeinen weltweit, das Webinhalte, meist statische Assets, verteilt und bereitstellt. Beliebte CDNs sind Cloudflare CDN, Amazon CloudFront und Fastly. Um ein CDN zu verwenden, laden Sie Ihre statischen Dateien hoch und referenzieren sie dann in Ihrer Anwendung wie folgt:

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

Dieser Prozess lässt sich einfach in Ihre Django-Bereitstellungsskripts integrieren. Nachdem Sie den Befehl python manage.py collectstatic ausgeführt haben, kopieren Sie das generierte Verzeichnis in Ihr CDN (ein Prozess, der je nach verwendetem Dienst erheblich variiert), und entfernen Sie dann die statischen Assets aus dem Django-Bereitstellungspaket.

In der Entwicklung möchten Sie möglicherweise auf andere Kopien Ihrer statischen Assets zugreifen als in der Produktion. So können Sie lokal Änderungen vornehmen, ohne den Produktionsstandort zu beeinträchtigen. Sie können entweder lokale Assets verwenden oder eine zweite Instanz des CDN ausführen, um die Dateien bereitzustellen. Konfigurieren Sie yourproject/settings.py mit einer benutzerdefinierten Variablen wie CDN_URL und verwenden Sie diesen Wert in Ihren Vorlagen, um sicherzustellen, dass Sie die richtige Version der Assets in der Entwicklung und Produktion verwenden.

Eine letzte Anmerkung ist, dass viele Bibliotheken für CSS und JavaScript kostenlose CDNs haben, die die meisten Websites verwenden können. Wenn Sie beispielsweise Bootstrap 4 oder underscore.js laden, können Sie den Aufwand für die Verwendung Ihrer eigenen Kopie in der Entwicklung und die Kosten für die Bereitstellung Ihrer eigenen Kopien in der Produktion überspringen, indem Sie diese öffentlichen CDNs verwenden.

Mediendateien mit einem dedizierten Dateispeicher

Keine Produktions-Django-Site sollte Benutzerdateien in einem einfachen /media/ -Ordner irgendwo auf dem Server speichern, auf dem die Site ausgeführt wird. Hier sind drei der vielen Gründe, warum Sie es nicht tun sollten:

  1. Wenn Sie die Site vergrößern müssen, indem Sie mehrere Server hinzufügen, benötigen Sie eine Möglichkeit, die hochgeladenen Dateien auf diesen Servern zu kopieren und zu synchronisieren.
  2. Wenn ein Server abstürzt, wird der Quellcode in Ihrem Versionskontrollsystem gesichert, aber Mediendateien werden standardmäßig nicht gesichert, es sei denn, Sie haben Ihren Server so konfiguriert, aber für diesen Aufwand sollten Sie besser ein dediziertes verwenden Dateispeicher.
  3. Im Falle böswilliger Aktivitäten ist es etwas besser, vom Benutzer hochgeladene Dateien auf einem anderen Server als dem, auf dem die Anwendung ausgeführt wird, aufzubewahren, obwohl dies in keiner Weise die Anforderung beseitigt, vom Benutzer hochgeladene Dateien zu validieren.

Die Integration eines Drittanbieters zum Speichern Ihrer vom Benutzer hochgeladenen Dateien ist wirklich einfach. Sie müssen nichts an Ihrem Code ändern, außer vielleicht den upload_to Wert von FileField s in Ihren Modellen zu entfernen oder zu ändern und einige Einstellungen zu konfigurieren. Wenn Sie beispielsweise vorhaben, Ihre Dateien in AWS S3 zu speichern, sollten Sie Folgendes tun, was dem Prozess zum Speichern von Dateien mit Google Cloud, Azure, Backblaze oder ähnlichen konkurrierenden Diensten sehr ähnlich ist.

Zuerst müssen Sie die Bibliotheken boto3 und django-storages storages installieren. Dann müssen Sie einen Bucket und eine IAM-Rolle auf AWS einrichten, was den Rahmen dieses Artikels sprengen würde, aber Sie können hier Anweisungen dafür sehen. Sobald das alles konfiguriert ist, müssen Sie drei Variablen zu Ihrer project/settings.py hinzufügen:

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

Darüber hinaus müssen Sie den Anmeldedatenzugriff auf Ihren AWS-Bucket einrichten. Einige Tutorials zeigen das Hinzufügen einer ID und eines geheimen Schlüssels zu Ihrer Einstellungsdatei oder als Umgebungsvariablen, aber dies sind unsichere Praktiken. Verwenden Sie stattdessen django-storages mit der AWS CLI, um die Schlüssel zu konfigurieren, wie hier beschrieben. Sie könnten auch an der Dokumentation zu django-storages interessiert sein.

Sie möchten nicht, dass Entwicklungs- oder Testmediendateien mit Uploads von tatsächlichen Benutzern vermischt werden. Dies zu vermeiden ist ziemlich einfach: Richten Sie mehrere Buckets ein, einen für die Entwicklung (oder einen für jeden Entwickler), einen zum Testen und einen für die Produktion. Dann müssen Sie nur noch die AWS_STORAGE_BUCKET_NAME Einstellung pro Umgebung ändern, und Sie können loslegen.

Leistung und Verfügbarkeit

Es gibt zahlreiche Faktoren, die die Leistung und Zuverlässigkeit Ihrer Website beeinflussen. Hier sind einige wichtige, wenn es um statische und Mediendateien geht, die unabhängig davon, welchen Ansatz Sie zu ihrer Verwaltung verfolgen, wichtig sind.

Kosten

Das Bereitstellen von Dateien für einen Benutzer kostet aus zwei Gründen Geld: Speicherplatz und Bandbreite. Sie müssen den Hosting-Provider dafür bezahlen, die Dateien für Sie zu speichern, aber Sie müssen ihn auch bezahlen, um die Dateien bereitzustellen. Die Bandbreite ist wesentlich teurer als die Speicherung (z. B. berechnet AWS S3 2,3 Cent pro Gigabyte für die Speicherung gegenüber 9 Cent pro Gigabyte für die Datenübertragung ins Internet zum Zeitpunkt des Schreibens). Die Wirtschaftlichkeit eines Dateispeichers wie S3 oder eines CDN unterscheidet sich von der Wirtschaftlichkeit eines generalisierten Hosts wie eines Digital Ocean-Tröpfchens. Profitieren Sie von Spezialisierung und Skaleneffekten, indem Sie teure Dateien in Dienste verschieben, die für sie entwickelt wurden. Darüber hinaus bieten viele Dateispeicher und CDNs kostenlose Pläne an, sodass Websites, die möglicherweise klein genug sind, um auf sie zu verzichten, dies stattdessen tun und die Vorteile ohne zusätzliche Infrastrukturkosten nutzen können.

Komprimierung und Transcodierung

Die meisten Probleme, die durch statische Assets wie Fotos und Videos verursacht werden, sind darauf zurückzuführen, dass es sich um große Dateien handelt. Natürlich gehen Entwickler dies an, indem sie versuchen, diese Dateien kleiner zu machen. Es gibt eine Reihe von Möglichkeiten, dies mit einer Mischung aus Komprimierung und Transcodierung in zwei allgemeine Kategorien zu tun: verlustfrei und verlustbehaftet. Die verlustfreie Komprimierung behält die ursprüngliche Qualität der Assets bei, bietet jedoch eine relativ geringe Verringerung der Dateigröße. Verlustbehaftete Komprimierung oder Transcodierung in ein verlustbehaftetes Format ermöglicht viel kleinere Dateigrößen auf Kosten des Verlusts eines Teils der Qualität des ursprünglichen Artefakts. Ein Beispiel hierfür ist das Transkodieren von Videos in eine niedrigere Bitrate. Weitere Informationen finden Sie in diesem Artikel zur Optimierung der Videobereitstellung. Bei der Bereitstellung großer Dateien über das Internet erfordern Bandbreitengeschwindigkeiten häufig die Bereitstellung stark komprimierter Artefakte, die eine verlustbehaftete Komprimierung erfordern.

Sofern Sie nicht YouTube sind, erfolgt die Komprimierung und Transcodierung nicht spontan. Statische Assets sollten vor der Bereitstellung entsprechend formatiert werden, und Sie können grundlegende Dateityp- und Dateigrößenbeschränkungen für Benutzer-Uploads durchsetzen, um eine ausreichende Komprimierung und angemessene Formatierung in den Mediendateien Ihrer Benutzer sicherzustellen.

Minimierung

Während JavaScript- und CSS-Dateien normalerweise nicht so groß wie Bilder sind, können sie oft komprimiert werden, um sie in weniger Bytes zu quetschen. Dieser Vorgang wird Minifizierung genannt. Die Verkleinerung ändert nicht die Codierung der Dateien, sie sind immer noch Text, und eine verkleinerte Datei muss immer noch gültiger Code für ihre Originalsprache sein. Minimierte Dateien behalten ihre ursprünglichen Erweiterungen.

In einer minimierten Datei werden vor allem unnötige Leerzeichen entfernt, und aus der Sicht des Computers sind fast alle Leerzeichen in CSS und JavaScript unnötig. Minimierungsschemata kürzen auch Variablennamen und entfernen Kommentare.

Die standardmäßige Minimierung verschleiert Code; Als Entwickler sollten Sie ausschließlich mit nicht-minifizierten Dateien arbeiten. Ein automatischer Schritt während des Bereitstellungsprozesses sollte die Dateien minimieren, bevor sie gespeichert und bereitgestellt werden. Wenn Sie eine Bibliothek verwenden, die von einem Drittanbieter-CDN bereitgestellt wird, stellen Sie sicher, dass Sie die minimierte Version dieser Bibliothek verwenden, falls verfügbar. HTML-Dateien können minimiert werden, aber da Django serverseitiges Rendering verwendet, würden die Verarbeitungskosten dafür höchstwahrscheinlich die geringe Verringerung der Seitengröße aufwiegen.

Globale Verfügbarkeit

Genauso wie es weniger Zeit in Anspruch nimmt, einen Brief an Ihren Nachbarn zu schicken, als ihn quer durchs Land zu schicken, dauert es auch weniger Zeit, Daten in der Nähe zu übertragen als in der ganzen Welt. Eine der Möglichkeiten, wie ein CDN die Seitenleistung verbessert, besteht darin, Assets auf Server auf der ganzen Welt zu kopieren. Wenn ein Client dann eine Anfrage stellt, erhält er die statischen Assets vom nächstgelegenen Server (oft als Edge-Knoten bezeichnet), wodurch die Ladezeiten verkürzt werden. Einer der Vorteile der Verwendung eines CDN mit einer Django-Site ist die Entkopplung der globalen Verteilung Ihrer statischen Assets von der globalen Verteilung Ihres Codes.

Clientseitiges Caching

Was ist besser, als eine statische Datei auf einem Server in der Nähe Ihres Benutzers zu haben? Wenn die statische Datei bereits auf dem Gerät Ihres Benutzers gespeichert ist! Zwischenspeichern ist der Vorgang des Speicherns der Ergebnisse einer Berechnung oder Anforderung, damit sie wiederholt schneller abgerufen werden können. So wie ein CSS-Stylesheet weltweit in einem CDN zwischengespeichert werden kann, kann es im Browser des Clients zwischengespeichert werden, wenn er zum ersten Mal eine Seite von Ihrer Website lädt. Dann ist das Stylesheet bei nachfolgenden Anfragen auf dem Gerät selbst verfügbar, sodass der Client weniger Anfragen stellt, die Seitenladezeit verbessert und die Bandbreitennutzung verringert.

Browser führen ihre eigenen Caching-Vorgänge durch, aber wenn Ihre Website erheblichen Datenverkehr hat, können Sie Ihr clientseitiges Caching-Verhalten mit dem Cache-Framework von Django optimieren.

Abschließend

Auch hier ist meine Leitphilosophie, Werkzeuge für das einzusetzen, was sie am besten können. Single-Server-Projekte und kleine skalierbare Bereitstellungen mit nur leichtgewichtigen statischen Assets können die integrierte Verwaltung statischer Assets von Django verwenden, aber die meisten Anwendungen sollten Assets trennen, die über ein CDN bereitgestellt werden sollen.

Wenn Ihr Projekt für irgendeine Art von realem Gebrauch gedacht ist, speichern Sie Mediendateien nicht mit der Standardmethode von Django, sondern verwenden Sie einen Dienst. Bei genügend Datenverkehr, wobei „genügend Datenverkehr“ eine relativ kleine Zahl auf der Skala des Internets ist, sind die zusätzlichen Komplikationen bei der Architektur, dem Entwicklungsprozess und der Bereitstellung mehr als wert für die Leistung, Zuverlässigkeit und Kosteneinsparungen bei der Verwendung von a separate CDN- und Dateispeicherlösung für statische bzw. Mediendateien.

Literatur-Empfehlungen

  • Teil 1: Benutzermodelle und Authentifizierung
  • Teil 2: Templating spart Zeilen
  • Teil 3: Modelle, Verwaltung und Nutzung der relationalen Datenbank