Untersuchen der Installation

Betrachten wir nun die bisherigen Verzeichnisse unseres Django-Projekts:

event_manager
    ├── manage.py
    ├── db.sqlite3
    └── event_manager
        ├── __init__.py
        ├── asgi.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py
    ├── requirements.txt
    ├── requirements-dev.txt
    ├── requirements.in
    ├── requirements-dev.in
.gitigore
...

das äußere event_manager/

Das äußere event_manager ist der Container für das gesamte Django-Projekt. Ein Django-Projekt besteht aus einer oder meist mehreren Apps, zum Beispiel einer Blog-App oder einem Webshop. Apps können völlig unabhängig sein oder von anderen Apps abhängen und mit ihnen kommunizieren.

Wir finden hier noch zwei weitere wichtige Dinge: das Programm manage.py und das Verzeichnis event_manager/.

manage.py

Ein kleines Helfertool, mit dem auf verschiedeneste Weise mit dem aktuellen Django-Projekt interagiert werden kann. Wir können damit die Verzeichnis-Struktur für Apps anlegen, Datenbanken migrieren, Daten im- und exportieren, Tests starten und vieles mehr.

Manage.py ist im Grunde das gleiche Programm wie django-admin, mit der Ausnahme, dass in manage.py die projektspezifischen Settings berücksichtigt werden. Django-Admin hingegen kennt diese Settings nicht. Deshalb ist manage.py für projektbezogene Arbeiten zu bevorzugen.

db.sqlite3

Die Default-Datenbank für das aktuelle Django-Projekt ist SQLite. Es handelt sich dabei um ein einfaches, aber dennoch mächtige relationales Datenbanksystem, das gerne im Entwicklungsprozess von Django-Applikationen eingesetzt wird. In Produktivumgebungen sollte sie allerdings nicht genutzt werden, da sie unter anderem schlecht skaliert und nicht so richtig multiuserfähig ist.

mehr dazu: https://stackoverflow.com/questions/6913833/using-sqlite-in-django-in-production

Das vorliegende Buch wird sqlite als Datenbank nutzen. Professionelle Projekte nutzen -wie in der Pythonwelt üblich- häufig Postgres.

das innere event_manager

Im inneren event_manager-Verzeichnis finden wir folgende Dateien vor:

__init__.py

Eine leere Datei, die Python mitteilt, dass dieses Verzeichnis als Python-Paket betrachtet werden soll. Wir werden diese Datei nicht weiter beachten in diesem Buch.

asgi.py

Der Einstiegspunkt für ASGI-kompatible Webserver für das Projekt. Asgi steht für asynchronous Gateway Interface und wird zum Beispiel für Chat-Programme oder Multiplayer-Games genutzt. In diesem Buch nutzen wir ASGI nicht.

wsgi.py

Der Einstiegspunkt für WSGI-kompatible Webserver für das Projekt. WSGI steht für Web Server Gateway Interface. Das Web Server Gateway Interface (WSGI) ist eine Schnittstellen-Spezifikation für die Programmiersprache Python, die eine Schnittstelle zwischen Webservern und Webframeworks bzw. Web Application Servern festlegt, um die Portabilität von Webanwendungen auf unterschiedlichen Webservern zu fördern. Ein Gunicorn Webserver beispielsweise für diese Datei als Einstiegspunkt nehmen:

gunicorn --bind 0.0.0.0:8000 event_manager.wsgi

Weiterführender Link:

https://www.fullstackpython.com/wsgi-servers.html

settings.py

Das sind die Projekteinstellungen. Hier werden die meisten Konfigurationselemente festgelegt, z. B. ob sich das Projekt im DEBUG-Modus befindet oder welche Datenbank genutzt wird. Die settings.py ist also die Haupt-Konfiguration. In der event_manager/event_manager/settings.py nehmen wir nun folgende Anpassungen vor:

Anpassen der Settings

Wir legen erstmal einen SECRET_KEY fest und definieren den erlaubten Host:

SECRET_KEY = "Ultralong42geheimer"
ALLOWED_HOSTS = ["127.0.0.1"]

Der SECRET_KEY dient Django als Basis für das Erstellen von kryptographischen Hash-Werten und wird zum Beispiel genutzt, um Passwort-Token oder CSRF-Token zu erstellen. Er muss auf alle Fälle geheim bleiben. Wir werden ihn später noch auslagern und anpassen.

ALLOWED_HOSTS

In dieser Liste werden die erlaubten Hosts eingetragen, um den vom User mitgesendeten Host-Header zu validieren. D.h. wenn die Seite später über infos.example.com ausgeliefert werden soll, trägt man die Domain hier genauso ein.

Wenn der Host-Header nicht validiert wird, kann ein Angreifer einen gefälschten Header-Wert senden, der für Cross-Site Request Forgery, Cache-Poisoning und dem Fälschen von Links in E-Mails verwendet werden kann.

Mehr zum Thema: https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html

Wir passen den DIRS-Key in den TEMPLATES an und setzen APP_DIRS auf True. Damit sagen wir Django, dass auch in den Apps nach Template-Dateien gesucht werden soll (später mehr zu Templates und Apps).

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",
        ],
        },
    },
]

und verändern die Zeitzone und Einstellungen zur Internationalisierung.

LANGUAGE_CODE = "de"
TIME_ZONE = "Europe/Berlin"
USE_I18N = True
USE_L10N = True
USE_TZ = True
wichtige Settings-Variablen

LANGUAGE_CODE

Default-Sprache der Website

TIME_ZONE

Zeitzone der Website

USE_I18N

ermöglicht den Umgang mit mehreren Sprachen

USE_L10N

ermöglicht die Lokalisierung (Format Von Zeit und Zahlen)

USE_TZ

speichert ein Datetime-Object immer in UTC

SECRET_KEY

Generierung von Hash-Schlüsseln

ALLOWED_HOSTS

Liste der erlaubten Hosts

urls.py

urls.py ist, wie der Name schon sagt, der Ort, an dem die URLs für das Projekt festgelegt werden. Obwohl wir nicht jede URL für das Projekt explizit in diese Datei schreiben werden, müssen wir in dieser Datei auf alle anderen Stellen hinweisen, an denen URLs deklariert wurden. URLs, die hier nicht gefunden werden, exisitieren für Django nicht.

Eine Beispiel-Url für das Abrufen aller im System befindlichen Events könnte zum Beispiel so aussehen: http://127.0.0.1:8000/events/show

URL Dispatcher

Gucken wir uns die event_manager/event_manager/urls.py mal genauer an. Wir finden dort -von Django vorgeneriert- unter anderem diesen Eintrag:

urlpatterns = [
    path('admin/', admin.site.urls),
]

urlpatterns ist eine Liste, die unsere URLs verwaltet und mit den entsprechenden Applikationen verknüpft. Jeder Eintrag entspricht einer konkreten Route, die wir via URL ansprechen können. Bisher haben wir noch keine Apps, deshalb ist die Liste bis auf einen Eintrag auch leer (das ist dir URL zu der Django-Administrationsoberfläche, die wir uns aber erst später ansehen werden).

To design URLs for an app, you create a Python module informally called a URLconf (URL configuration). This module is pure Python code and is a mapping between URL path expressions to Python functions (your views).

This mapping can be as short or as long as needed. It can reference other mappings. And, because it’s pure Python code, it can be constructed dynamically.

—Django Documentation, URL dispatcher

In unseren Url-Definitionen innerhalb der urlpatterns interessiert uns der Domainname übrigens nicht (in diesem Fall http://127.0.0.1). Auch der Port 8000 ist für uns uninteressant. Wo unser Projekt später liegt, dh. über welche Domain oder welchen Port es angesprochen wird, ist für uns also vollkommen uninteressant. Im Gegenteil, wir wollen sogar vermeiden, dass unser Projekt in irgendeiner Form an eine Domain gebunden ist, um das Projekt möglichst portierbar zu halten.

Was uns allerdings interessiert, ist der sogenannte URL-Pfad. Für uns also ist nur der Teil events/show der URL http://example.com/events/show interessant.

Im Laufe eines Projekts wird die urlpatterns-Liste immer weiter anwachsen, da immer mehr Routen und damit URLs hinzukommen werden. Es bietet sich an, hier von Anfang an penibel auf Ordnung zu achten.

URL Design

Jedes moderne Web-Projekt sollte ein ordentliches URL-Design haben. Urls sollten sich auch nach einem Redesign/Neu-Entwicklung im Idealfall nicht ändern, da andere Resourcen womöglich auf das Projekt verlinken, und diese URLs dann nicht mehr stimmen würden. Freilich gibt es serverseitige Techniken, diese nicht-existenten URLs umzuschreiben.

eine gute URL zum Anlegen/Löschen eines Users schaut zum Beispiel so aus:

ein schlechtes Beispiel für die gleiche Aufgabe

Konsistenz

Beim URL-Design sollte auf Konsistenz geachtet werden

https://www.deepcrawl.com/blog/best-practice/guide-to-url-design/ https://www.w3.org/Provider/Style/URI

Mehr zum Thema URL-Resolving in der Django Doku: https://docs.djangoproject.com/en/stable/topics/http/urls/