.. _directory_structure: .. index:: single: manage.py single: urls.py single: Sqlite single: Projektverzeichnis single: URL-Design Untersuchen der Installation **************************** Betrachten wir nun die bisherigen Verzeichnisse unseres Django-Projekts: .. code-block:: shell 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. weiterführender Link: ....................... ``_ 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: ``_ 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: .. code-block:: bash gunicorn --bind 0.0.0.0:8000 event_manager.wsgi Weiterführender Link: .......................... ``_ 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: .. code-block:: python 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. .. admonition:: 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:** ``_ 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). .. 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", ], }, }, ] und verändern die Zeitzone und Einstellungen zur Internationalisierung. .. code-block:: python LANGUAGE_CODE = "de" TIME_ZONE = "Europe/Berlin" USE_I18N = True USE_L10N = True USE_TZ = True .. csv-table:: wichtige Settings-Variablen :widths: 20, 60 ``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: .. code-block:: python 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. .. admonition:: 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:** | http://127.0.0.1:8000/user/create | http://127.0.0.1:8000/user/343/delete **ein schlechtes Beispiel für die gleiche Aufgabe** | http://127.0.0.1:8000/code/user_verwalten.php?add=true | http://127.0.0.1:8000/code/user_verwalten.php?delete=true&id=343 **Konsistenz** | Beim URL-Design sollte auf Konsistenz geachtet werden | **gut** | http://127.0.0.1:8000/user/create | http://127.0.0.1:8000/user/343 | http://127.0.0.1:8000/user/343/delete | http://127.0.0.1:8000/user/343/update | **schlecht** | http://127.0.0.1:8000/create/user | http://127.0.0.1:8000/user/343/delete | http://127.0.0.1:8000/edit-user/343 | http://127.0.0.1:8000/user/detail/343 ``_ ``_ **Mehr zum Thema URL-Resolving in der Django Doku:** ``_