Statische Dateien einbinden

Statische Dateien sind zum Beispiel Bilder oder CSS-Dateien. Also alles, was nicht dynamisch ist. Um diese Dateien über unseren Server auszuliefern, müssen wir folgende Schritte tun.

Statische Dateien in den Settings

Wir müssen in der event_manager/settings.py folgende Code-Zeilen einfügen:

In den Apps muss django.contrib.staticfiles vorhanden sein:

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "django.contrib.admindocs",
]

Diese drei Konstanten müssen gesetzt sein:

STATIC_ROOT = BASE_DIR / "staticfiles"
STATIC_URL = "/static/"
STATICFILES_DIRS = [
    BASE_DIR / "static"
]
MEDIA_ROOT = BASE_DIR / "media"
MEDIA_URL = "/media/"
  • STATIC_URL: das ist der URL-Pfad, über den die statischen Dateien erreichbar sind, zb. http://127.0.0.1:8000/static/css/bootstrap.css

  • STATICFILES_DIRS: hier liegen die statischen Dateien, zb. event_manager/static für projektweite statische Assets.

  • STATIC_ROOT: der Ort, an dem alle statischen Daten für ein einfacheres Deploment gesammelt werden. Dazu wird das Kommando python manage.py collectstatic ausgeführt.

  • MEDIA_ROOT: hier liegt der von Usern hochgeladene Media-Content wie Bilder, PDFs oder Doc-Dateien. Auch Bilder der eigenen Blog-App liegen unter diesem Verzeichnis.

  • MEDIA_URL: das ist der URL-Pfad, über den die Mediendateien erreichbar sind, zb. http://127.0.0.1:8000/media/images/holiday_1.jpg

Statische Dateien in der Produktivumgebung

in einer Produktivumgebung sollten Dateien auf gar keinen Fall über den WSGI-Server ausgeliefert werden, dieser ist ausschließlich dazu da, mit der Pythonapplikation zu kommunizieren. Entweder ist Nginx so konfiguriert, dass es die Dateien separat ausliefert, oder bevorzugt wird ein Content Delivery Network wie AWS benutzt werden, um statische Dateien auszuliefern.

Eine einfache Alternative zu kostenpflichtigen CDNs ist das Modul whitenoise. Dieses liefert statische Dateien zwarüber den Python-Webserver aus, das aber so geschickt, dass die Performance nicht darunter leidet. Whitenose ist allerdings nur für kleinere bis mittlere Projekt geeignet.

Meht dazu unter https://docs.djangoproject.com/en/4.0/howto/static-files/deployment/ Whitenoise: http://whitenoise.evans.io/en/stable/

Verzeichnisse anlegen

Wir legen ein Verzeichnis für die projektweiten statischen Dateien an: event_manager/static

Und speichern uns den Inhalt von https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css in der Datei event_manager/static/css/bootstrap.min.css

und ändern das event_manager/templates/base.html-Template ab:

<!-- Einfügen von load static, um auf statische Dateien referenzieren -->
{% load static %}

und ersetzen diese Zeile:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

durch diese hier:
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">

Wenn wir uns den HTML-Quellcode ansehen, sollte nicht mehr auf die URL sondern auf unseren static-Ordner referenziert werden. Trotzdem sollte der Look noch genauso sein, wie vorher.

Collect Static Files

In der Entwicklungsumgebung (Debug=True) liefert der Runserver neben dem HTML auch die statischen Dateien aus. Das ist vollkommen in Ordnung und richtig so. Allerdings ist das in einer Produktivumgebung (Debug=False) nicht zu empfehlen.

Wenn wir unsere Applikation in eine Live-Umgebung deployen wollten, würden die statischen Dateien momentan noch nicht ausgeliefert werden. Ob eine Produktiv-Umgebung vorliegt, entscheidet die Settings-Variable DEBUG. Ist diese False, befinden wir uns laut Django in einer Produktiv-Umgebung.

Zusätzlich kommt noch dazu, das sich womöglich gar nicht alle statischen Dateien in einem bestimmten Ordner befinden, sondern über viele Apps und Verzeichnisse verstreut sind.

Django bietet einen sehr intelligenten Mechanismus an, statische Dateien an einem Ort zu sammeln und alle über ein Verzeichnis gemeinsam verfügbar zu machen. In einem weiteren Schritt könnt man dann den Webserver oder Nginx auf dieses Verzeichnis zeigen.

Dazu müssten wir erstmal folgendes Kommando ausführen:

python manage.py collectstatic

Collectstatic sammelt alle statischen Dateien im Verzeichnis STATIC_ROOT. Dieses Verzeichnis könnte dann zum Beispiel an ein CDN hochgeladen und vor dort aus ausgeliefert werden.

Best Practice: Versionierung von statischen Dateien

Die mit python manage.py collectstatic gesammelten Dateien sollten nicht versioniert werden. Diese Aktion sollte als Teil der Deployment-Pipeline automatisiert auf dem Server ausgeführt werden, zb. als Service in docker-compose oder git-posthook.

Diese beiden Einträge sollten der .gitignore-Datei hinzufügt werden.

  • media/

  • staticfiles/

Media

Was für die statischen CSS-und JS-Dateien gilt, gilt umsomehr für Medien wie zum Beispiel von Usern hochgeladene Bilder für Blog-Artikel oder PDF-Dateien. Diese sind potentiell gefährlich und können Schadcode enthalten!

Auch diese Medien-Dateinen sollten über einen anderen Webserver ausgeliefert werden, als die Django-Applikation. Ideal wäre besonders hier, über einen professionellen CDN wie AWS auszuliefern.

Statische Dateien deployen

Dieses Kapitel ist zu umfangreich, um es hier abzudecken. Kurz ein paar weiterführende Links:

https://docs.djangoproject.com/en/4.0/howto/static-files/deployment/ https://docs.djangoproject.com/en/4.0/ref/settings/#std:setting-STATICFILES_STORAGE

Relativ problemlos lassen sich statische Dateien mit Whitenoise nutzen: https://learndjango.com/tutorials/django-static-files