.. _static_files:
.. index::
single: Statische Dateien
single: contrib.staticfiles
single: STATIC_ROOT
single: STATICFILES_DIRS
single: STATIC_URL
single: collectstatic
single: Nginx
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:
.. code-block:: python
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.admindocs",
]
Diese fünf Konstanten müssen gesetzt sein:
.. code-block:: python
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
Deployment gesammelt werden. Dazu wird das Kommando ``python manage.py
collectstatic`` ausgeführt. Später kann man dann zum Beispiel den Webserver
so konfigurieren, dass HTTP-Anfragen an statische Dateien an dieses
Verzeichnis geroutet werden sollen. Dieser Ordner muss auch nicht auf dem gleichen Server
liegen. Denkbar und nicht unüblich ist es, statische Daten über einen ``CDN``
auszuliefern.
* ``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
.. admonition:: 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 aus einem separaten Verzeichnis ausliefert,
oder es wird ein Content Delivery Network wie ``AWS`` oder ein sonstiger ``Object Storage`` genutzt, um statische Assets auszuliefern.
Eine einfache Alternative zu kostenpflichtigen ``CDNs`` ist das Modul
``whitenoise``. Dieses liefert statische Dateien zwar über den
wsgi-kompatiblen 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 ``_
Whitenoise: ``_
Verzeichnisse anlegen
-------------------------
Wir hatten das Verzeichnis für statische Dateien schon im Kapitel **Templates
ausbauen** angelegt:
.. code-block:: bash
├── event_manager
│ ├── event_manager
│ │ ├── settings.py
│ ├── events
│ ├── manage.py
│ ├── static
│ │ ├── css
│ │ │ └── style.css
│ │ └── images
│ │ └── penglogo.png
│ └── user
Und speichern uns den Inhalt von ``https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css`` in der Datei ``event_manager/static/css/bootstrap.min.css``
und ändern das ``event_manager/templates/base.html``-Template ab:
.. code-block:: bash
{% load static %}
und ersetzen diese Zeile:
durch diese hier:
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.
This method is grossly inefficient and probably insecure, so it is unsuitable for production.
--Django Docs, https://docs.djangoproject.com/en/stable/howto/static-files/
Wenn wir unsere Applikation in einer Live-Umgebung deployen wollten, würden die
statischen Dateien momentan also 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. Django verhindert, dass statische
Dateien in der Produktiv-Umgebung über die WSGI-Schnittstelle ausgegeben werden,
um Performance und Sicherheit zu gewährleisten.
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.
Dazu müssten wir erstmal folgendes Kommando ausführen:
.. code-block:: bash
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.
.. admonition:: 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/
.. admonition:: 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:
``_
``_
Relativ problemlos lassen sich statische Dateien mit ``Whitenoise`` nutzen:
``_
**Weiterführende Links:**
----------------------------
* ``_
* ``_