.. _context_processors:
Context Processors
************************
Manchmal ist es notwendig, Werte aus der Datenbank auf allen Seiten der
Website auszugeben, zum Beispiel der Name der Website.
Konkret heisst das für uns, dass jede View zusätzlich noch ein weiteres Objekt im Kontext an das
Template überreichen müsste. Das klingt ziemlich aufwändig.
Natürlich könnte man den Wert auch hardkodiert in den Settings hinterlegen, nur wäre er dann
nicht von Moderatoren oder anderen Staff-Membern editierbar. Bei einer Änderung
an den Settings müsste das System neu deployed werden. Besser wäre es, wenn wir
solche Aufgaben über die Administrationsoberfläche lösen könnten.
Mit den Methoden, die wir bisher kennengelernt haben, ist das aufwändig.
Was ist ein Context-Prozessor?
-------------------------------
Mit Context-Prozessoren wird zusätzlicher Kontext an die Template-Engine
übergeben, ohne ihn explizit in jeder View mit angeben zu müssen, was sehr
müheslig wäre. Django besitzt schon ein paar ``built-in`` Context-Prozessoren, zum Beispiel das Übergeben der Success-Messages an eine View.
Diese Kontext-Prozessoren sind in der ``settings.py`` in der ``TEMPLATES``-Konstante angelegt. Der
Message-Kontextprozessor sieht zum Beispiel so aus:
``django.contrib.messages.context_processors.messages``
Eigene Context-Prozessoren entwickeln
--------------------------------------
Wir können natürlich auch eigene Kontext-Prozessoren entwickeln und in den
Settings hinterlegen. Wir wollen jetzt den Namen der Website über die
Administrationsoberfläche verfügbar machen und über einen Kontext-Prozessor auf
jeder View ausgeben.
Es bietet sich also an, für System-Settings ein eigenes Modell anzulegen, das
später über die Administrationsoberfläche editiert werden kann.
Django Site Framework
------------------------
Django wird mit dem sogenannten Sites-Framework ausgeliefert, welches uns
ermöglicht, für unser Projekt Namen und Web-Adresse in der Datenbank zu
spezifieren. Wir können auch mehrere solcher ``Sites`` anlegen und könnten dann
in Abhängigkeit von der genutzten Domain unterschiedlichen Content ausgeben.
Dies ist besonders nützlich, wenn wir mehrere Websites mit einer einzigen
Codebase (zum Beispiel in einem Content-Management-System) oder mehrere Websites mit
einer gemeinsamen Datenbank verwalten.
Das wollen wir hier in diesem Buch allerdings nicht weiter vertiefen. Uns
reicht die Möglichkeit, einen festen Namen und eine Web-Adresse für unsere SITE in der Admin zu
hinterlegen und editierbar zu machen.
**Mehr zu dem Thema findet sich in der Django-Doku:**
``_
Um das Sites-Framework zu installieren, müssen wir es nur in den
``INSTALLED_APPS`` in den ``event_manager/event_manager/settings/base.py`` eintragen.
.. code-block:: python
INSTALLED_APPS = [
...
"django.contrib.sites",
...
]
und ebenfalls in der ``event_manager/event_manager/settings/base.py`` die
Middleware hinzufügen.
.. code-block:: python
MIDDLEWARE = [
...
"django.contrib.sites.middleware.CurrentSiteMiddleware",
...
]
Nun führen wir die Migration aus:
.. code-block:: bash
(eventenv) python manage.py migrate
Running migrations:
Applying sites.0001_initial... OK
Applying sites.0002_alter_domain_unique... OK
und schon ist das ``Sites-Framework`` installiert.
In den Settings unter ``event_manager/event_manager/settings/base.py`` können
wir jetzt noch die SITE_ID festlegen. Diese setzen wir auf 1 (weil wir auch nur
eine Site festlegen).
.. code-block:: python
SITE_ID = 1
Die Admin Oberfläche
----------------------
Wenn wir jetzt die Administrationsoberfläche öffnen, sehen wir auf der linken
Seite einen neuen Eintrag namens ``Webseiten``.
.. image:: /images/django_sites_1.png
Wir können jetzt den Namen der Webseite (Anzeigename) und die Adresse ändern
und speichern. Momentan hat das noch keinen Einfluss auf unsere Website, da wir
die Daten bisher nicht ausgeben.
.. image:: /images/django_sites_2.png
Unser Context Processor
------------------------
Wir wollen den ``Anzeigename`` unserer ``Site`` jetzt in der Top-Navigation unserer Webseite ausgeben.
Wenn wir den bisherigen Weg gehen wollten, müssten wir
jetzt jeder View diesen Wert hinzufügen. Sehr umständlich.
Wir gehen den Weg über den Context Processor.
Unter ``event_manager/event_manager`` legen wir die Datei ``context_processors.py``
an. Diese Datei enthält eine Funktion, die ein Kontext-Dictionary zurückgibt.
.. code-block:: python
from django.contrib.sites.models import Site
def get_site_infos(request):
current_site_name = Site.objects.get_current().name
current_site_domain = Site.objects.get_current().domain
return {'site_name':current_site_name, 'site_domain': current_site_domain}
``get_site_infosa`` ist ein benutzerdefinierter Kontextprozessor, den wir
gerade erstellt haben. Wir können diesen jetzt den ``context_processors`` in den
``TEMPLATES"``-Settings unter ``event_manager/eventmanager/settings/base.py`` hinzufügen.
Der Key ``site_name`` aus dem zurückgegebenem Dictionary ist dann als
Template-Variable in allen Templates zugänglich.
.. code-block:: python
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "event_manager" / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"event_manager.context_processors.get_site_infos",
],
},
},
]
Das Template anpassen
----------------------
Wir wollen den Website-Namen jetzt überall auf unserer Website ausgeben.
Deshalb öffnen wir das base-Template unter
``event_manager/event_manager/templates/base.html`` und geben die
Kontextvariable ``site_name`` aus.
Etwa in Zeile 23 der ``base.html`` fügen wir nach dem img-Tag des Logos noch den site_name ein:
.. code-block:: html+django
...
{{site_name}}
...
Wenn wir die Website unter ``http://127.0.0.1`` neu laden, sollte der Name der
Webseite oben links neben dem Pinguin-Logo erscheinen.
**Mehr zum Thema Context Processor in der Django Doku:**
* ``_
Optional: Das Projekt in der Version v0.4 kopieren
-----------------------------------------------------
Wie immer kann man sich den Zwischenstand klonen, falls beim Mitschreiben was
schiefgegangen ist.
Version v0.5 via github clonen
......................................
.. code-block:: bash
git clone -b v0.5 git@github.com:realcaptainsolaris/event_project.git
und dann nicht vergessen, ein virtuelles Environment anzulegen und zu
migrieren und danach noch ein paar Testdaten zu generieren:
.. code-block:: bash
python -m venv .envs/eventenv
pip install pip-tools
pip-sync requirements.txt requirements-dev.txt
python manage.py migrate
python manage.py createsuperuser
python manage.py create_user -n 10
python manage.py create_events --events 20 --categories 5
python manage.py runserver
Version v0.5 als zip-Datei runterladen
...........................................
``_
Version v0.5 als tar-Datei runterladen
............................................
``_