DIVING INTO DJANGO

Technologiepraktikum | eXXcellent solutions GmbH

Prominente Django Projekte

... und noch viele mehr

AGENDA

AGENDA

  1. Was ist Django?
  2. Die erste Django-App
  3. Templates
  4. Datenhaltung
  5. Migrationen
  6. Forms
  7. (Generic) Class-Based-Views
  8. Django-Admin
  9. Django-REST-Framework

KAPITELSCHEMA

KAPITELSCHEMA

🤔 Kompakter Theorieteil → Hands-On! 🤩

Die Praxisteile erfordern Webrecherche! Heißt:

Zuerst kurz fragen

...denn die Django-Doku ist wirklich hervorragend!

dann eventuellen -Button öffnen

und dann uns ansprechen.

... wenn du trotzdem noch Unterstützung brauchst oder Fragen hast 🤷‍♂

Was ist Django?

Was ist Django?

  • Fullstack-Framework
  • Don't Repeat Yourself
  • Client-Server Architektur (Request-Response-Schema)

ARCHITEKTUR

Du bist dran

beim Projekt-Setup

Hier gehts zur Aufgabe

  1. Projekt auschecken:
    https://gitlab.exxcellent.de/wwermund/tp-diving-into-django.git
  2. Projekt in PyCharm öffnen

Python-Remote-Interpreter anlegen

[strg] + [shift] + [a] → "python interpreter"

Leeres Django-Projekt anlegen (lassen 😀)

im Terminal in PyCharm:

docker-compose run django django-admin startproject photogallery .
"run" zieht dabei einen neuen Docker-Container hoch. Wenn später bereits ein Docker-Container läuft, kann stattdessen "exec" verwendet werden.

Django-IDE-Unterstützung aktivieren

Einstellungen von PyCharm öffnen

Run-Configuration für Development-Server anlegen

[strg] + [shift] + [a] → "Edit Configurations ..."

Development-Server starten

Im Browser http://localhost:8000/ aufrufen

🎉 Fertig 🎉

Wenn du noch Zeit hast, dann erkunde doch ein wenig die Verzeichnisstruktur & Dateien, die Django dir angelegt hat

VERZEICHNISSTRUKTUR


PROJEKT_ROOT
|-+ photogallery         # Django-Projekt-Verzeichnis
|   |-- asgi.py
|   |-- settings.py      # Einstellungen zum Django-Projekt
|   |-- urls.py          # URL-Definition für den Dispatcher
|   |-- wsgi.py
|-+ app1                 # Django-App 1
|   |-- migrations       # Migrationen
|   |-- templates        # Templates
|   |-- models.py        # Models
|   |-- views.py         # Views
|-- app2                 # Django-App 2
|-- manage.py            # Verwaltungsskript
            

Die erste App

Die erste App

  • Apps sollen reusable sein → Projekt in logische Einheiten teilen
  • Anlegen neuer App
    docker-compose run django python manage.py startapp my_first_app
  • Anschließend in INSTALLED_APPS innerhalb der "settings.py" eintragen

Der erste View

Der erste View

„Views sind Python-Methoden, die einen Request entgegen nehmen und mit einem Response antworten“ Zitat: Die Tutoren (heute)

Der erste View

  • werden über eine/mehrere Path(s) angesprochen
  • Dispatcher weiß dadurch ob/was er tun muss
  • Pflege der Zuordnungen in "urls.py"

Beispiel


                

                

Und jetzt dein

erster View!

Hier gehts zur Aufgabe

  1. Erstelle in deinem Projekt eine neue App "first_app"
  1. Lege in dieser neuen App einen View an, der eine Zahl anzeigt und einen Link anbietet, um die Zahl um 1 zu erhöhen, sowie einen weiteren Link um die Zahl um 1 zu verringern

    So ähnlich sollte es aussehen:

    Werf doch mal einen Blick auf folgende Doku: Django URL-Dispatcher

  1. Lege einen weiteren View an, der den Benutzer nach einem Namen fragt

    Der Name soll abgesendet werden können und anschließend den Benutzer mit seinem Namen freundlich begrüßen. Außerdem soll die Begrüßungsseite einen Link zurück zur Namenseingabe enthalten.

    Dein Formular im HTML setzt normalerweise ein POST-Request ab. Die Daten daraus kannst du aus dem request-Parameter deines Views auslesen.

🎉 Fertig 🎉

Wenn du noch Zeit hast, versuche doch auf eine Falscheingabe (leer?) des Namens in Aufgabe 3 mit einer entsprechenden Meldung zu reagieren.

Templates

Was versteht Django unter Templates?

  • Plain-Text-Dateien
    + Template-Syntax
    + Daten-Kontext
  • Verschiedene Template-Sprachen verfügbar
  • Möglichst wenig „Logik“

D
jango
T
emplate
L
anguage

  • Mitgeliefert + Standard
  • Variablen: Befüllt durch Kontext
  • Filter: Ändern den Wert einer Variablen und geben ihn aus
  • Tags: Kontrollstrukturen und mehr
  • Kommentare
  • Vererbung
  • Hier gehts zur Doku

Beispiel
Basistemplate


                

Beispiel
Seitentemplate


                

Du bist dran:

Dein erstes Template!

Hier gehts zur Aufgabe

  1. Lege in deiner „first_app“ ein neues Verzeichnis „templates“ an. Platziere dort eine neue „first_template.html“ (Rechtsklick auf den Ordner -> „New“ -> „HTML File“) und fülle den Body mit etwas Text. Lege einen neuen View sowie Route an, der die neue „first_template.html“ über den „render()“-Shortcut (Django-Render-Shortcut) ausgibt.
  1. Deine Laufzeitumgebung enthält schon eine Fremd-App namens „bootstrap4“ die das Bootstrap-CSS-Framework bereitstellt.
    Die Library bietet verschiedene Template-Tags an, die eine Einbindung der Static-Files von Bootstrap erleichtern. Binde die App „bootstrap4“ in dein Projekt ein („settings.py“). Lege ein neues Template „first_bootstrap_template.html“ an und binde die CSS und JS Teile im Head des Dokumentes ein (Django-Bootstrap4-Doku).
    Teste alles mithilfe eines neuen Views, Route + einigen Features des Bootstrap Frameworks (z.B. Alerts etc.).
  2. Diese Zeilen müssen in den <head> deines HTML-Dokumentes. Anschließend kannst du Bootstrap vollumfänglich in deinem Template nutzen!

  1. Kopiere das Template aus 2. als „base.html“. Dieses soll als Basis für beliebige Seiten verwendet werden können. Hier enthalten sein sollen alle Teile, die nicht spezifisch einer bestimmten Seite zugeordnet werden können (Header, Imports, evtl. Basislayout der Anwendung). Ersetze alle Stellen, die Inhalt enthalten, durch Blöcke, die durch spätere Templates dann mit Inhalten gefüllt werden können (DTL-Doku). Erstelle ein weiteres Template, das die gleiche Seite erzeugt wie 2., aber selbst nur das „base.html“ extended und die notwendigen Blöcke befüllt. Zeige die Seite über einen eigenen View + Route an.
  1. Lege ein Template an, das vom View per Kontext eine Liste von (deinen Lieblings-😄) Serientitel erhält und diese in einer zweispaltigen Bootstrap Tabelle anzeigt. Titel, die ein Leerzeichen enthalten, sollen dabei mit dem Info-Background (Blau) hinterlegt werden. Die Nummer des Titels kannst du vom View aus mitgeben - musst du aber nicht. Versuche es auch mal ohne 😄

🎉 Fertig 🎉

Wenn du noch Zeit hast, dann trinke einen ☕
oder schau dir dieses informative Video an.

„You have been rickrolled!“ 😜
Dafür jetzt ein wirklich sinnvoller Hinweis: Jinja2 ist eine weitere Templating-Sprache die offiziell von Django unterstützt wird. Werf doch mal einen Blick in deren Doku!

Datenhaltung

aka. „Models“

Wie funktioniert Datenhaltung in Django?

  • Integrierter ORM
  • Tatsächliche DB für den Entwickler i.d.R. transparent
  • „Models“ = Klassen, die alle persistenten Daten enthalten (in „models.py“)
  • Automatisch generierte Migrationen für Model-Änderungen
  • Feld-Typen-Dokumentation von Django

Beispiel

Und jetzt

deine eigenen Models

Hier gehts zur Aufgabe

  1. Lege eine neue App „gallery“ an. Diese App werden wir im Laufe dieses Praktikums immer weiter zu einer vollwertigen Fotogalerie weiterentwickeln.
  2. Lege in der App „gallery“ ein Model (soll ein Foto repräsentieren) mit folgenden Attributen (passender Datentyp!) an: file (benötigt), title (optional), capture_date (optional)

    file: ImageField, title: CharField, capture_date: DateTimeField

  1. Lasse von Django entsprechende Migrationen erstellen und migriere deine Datenbank.
  2. Damit Django weiß, wo vom Benutzer hochgeladene Dateien etc. gespeichert werden sollen, muss man zwei Parameter in settings.py setzen:
    • MEDIA_ROOT: Absoluter Pfad zu einem Ordner, in dem die Dateien gespeichert werden sollen (z.B. „os.path.join(BASE_DIR, 'media_root/')“)
    • MEDIA_URL: URL unter der die hochgeladenen Daten angeboten werden (z.B. „/media/“)

    MEDIA_ROOT und MEDIA_URL sind nicht ganz trivial zu verstehen. Im Endeffekt zeigt MEDIA_ROOT auf einen tatsächlichen Ordner deines Dateisystems in den Django dann alle Dateien packen kann, die irgendwohin müssen. Die MEDIA_URL wird automatisch vor alle URLs gepackt, die auf Dateien in genau diesem Ordner zeigen sollen - hierdurch ist z.B. auch möglich das Bereitstellen der Dateien auf einem völlig anderen Server zu realisieren. Vielleicht schießt dir da ja gleich ein S3-Bucket durch den Kopf 😄?

  1. Letztendlich müssen die Dateien auch tatsächlich von irgendeinem Server über eine URL angeboten werden (in Production übernimmt das z.B. nginx oder Apache) - für unsere Entwicklungsumgebung können wir da den Development-Server bemühen. Folge hierfür der offiziellen Anleitung.
  2. Lege zu allen Beispielfotos im Ordner „example_data/photos“ Instanzen über die interaktive Konsole an und fülle sie mit entsprechenden Daten (hilfreiche Doku).
    Denke daran, dass du eine der mächtigsten Skript-Sprachen zur Hand hast. Vielleicht kann sie dir Arbeit abnehmen? 😄

    Python kann dir alle Dateien eines Verzeichnisses ausgeben (os.listdir()). Darüber zu iterieren bekommst du selbst hin 👍

  1. Erstelle einen neuen View („Galerieansicht“), der alle aktuell vorhandenen Fotos aus der Datenbank läd und in einer Kachelansicht anzeigt. Denke an ein sinnvolles Basis-Template von dem deine restlichen Templates ableiten. Einzelne Apps können auch selbst URLs definieren, die dann vom Gesamtprojekt eingebunden werden können (auch z.B. unter einem Präfix-Pfad) - das kann in vielen Fällen sinnvoll sein, um die „urls.py“ übersichtlich zu halten. Lege eine eigene „urls.py“ für deine „gallery“-App an und pflege die URLs, welche die Fotogalerie betreffen zukünftig dort (wie?). Es ist schwer zu empfehlen zumindest einmal die Doku zu jedem Template-Tag/-Filter zu lesen (am einfachsten, wenn du ihn das erste mal verwendest): Template-Tag-Doku

🎉 Fertig 🎉

Wenn du noch Zeit hast, stöbere doch mal in folgender Homepage:
Django-Packages
Sie enthält eine gigantische Sammlung an fertigen Libraries/Tools für deine Arbeit mit Django. Fast alles hat jemand schon mal gelöst - don't reinvent the wheel!

Datenbank-Migrationen

🎉 Nie wieder SQL 🎉

Django-Database-Migrations

  • existieren pro App
  • überführen von einem Datenbankstand in einen neuen
  • vollständig datenbank-unabhängig
  • Python-Source-Code
  • Teil des Projektes → einchecken!
  • ausgeliefert? → nie wieder verändern!
  • = App kann aus jedem Entwicklungsstand heraus auf die neueste Version gehoben werden

manage.py makemigrations

  • erstellt in 95% der Fälle Migrationen automatisch/interaktiv
  • restliche Fälle: Datenmigrationen
    • werden auch als Python-Source-Code geschrieben und funktionieren über dieselben Mechanismen

Lass Django

die Migrationen machen!

Hier gehts zur Aufgabe

  1. Füge ein weiteres optionales Attribut „comment“ zum Foto-Model hinzu, in dem ein längerer Freitext-Kommentar zum Bild gespeichert werden kann.
  1. Die Galerieansicht ist aktuell nicht sehr performant, da alle Bilder in voller Auflösung an den Client übertragen werden müssen, obwohl wir eigentlich nur eine kleine Version des Bildes anzeigen. In deiner Entwicklungsumgebung ist schon eine Django-App „sorl.thumbnail“ enthalten, die hier Abhilfe schaffen kann. Verwende das dort mitgelieferte „ImageField“ in deinem Foto-Model und passe deine Templates entsprechend an.

Bonusaufgabe

  1. Füge zwei neue required und nicht editierbare Attribute „width“ und „height“ hinzu, die entsprechend die Höhe + Breite des Fotos enthalten. Bestehende Instanzen müssen hierzu den Wert über eine Datenmigration erhalten. Bewährt hat sich hier folgendes Vorgehen:
    • Feld in einer Migration als optional anlegen
    • Über Datenmigration befüllen
    • Feld zu required ändern

    Dein Projekt enthält schon Pillow - eine Library um in Python mit Rastergrafiken umzugehen. Das ImageField hat ein Attribut "file", das du mit Pillow öffnen kannst um an die Informationen des Bildes (wie z.B. die Größe) zu kommen.

🎉 Fertig 🎉

Noch Zeit übrig? Lies dich doch etwas in die Django Debug Toolbar ein - ein wirklich cooles Tool um deine Views etc. übersichtlich zu debuggen!

Forms

Was sind Django-Forms?

Beispiel



            


            

Model-Forms

Automatische Erstellung einer Form aus einem Model



            


            

Erzeugter HTML-Code



            

Jetzt deine

eigenen Forms

Hier gehts zur Aufgabe

  1. Erstelle ein neues Model „Person“ in deiner „first_app“ mit folgenden Attributen:
    • first_name (required, String)
    • last_name (required, String)
    • birthday (required, Date)
    • favourite_beverage (required, Einfachauswahl)
      • Geburtstage dürfen nicht in der Zukunft liegen (siehe hier)
    • friends (optional, M2M zu Person)
    Der Vorname darf im Falle eines Nachnamens „Mustermann“ nicht „Max“ lauten (siehe hierzu .clean() )
  1. Erstelle einen View + Template um eine Person über ein ModelForm anzulegen. Validierungsfehler sollen angezeigt werden.
  2. Erstelle einen View + Template um eine Person über ein ModelForm zu editieren. Validierungsfehler sollen angezeigt werden.

Bonusaufgabe

  1. So richtig toll sehen die Forms aktuell vermutlich nicht aus - natürlich hast du die Möglichkeit das Formular von Hand über Bootstrap-Klassen zu stylen. Das bedeutet jedoch auch, dass du deine Templates bei jeder Änderung an den Models anfassen musst. Django has you covered!
    Dein Projekt enthält eine Django-App namens crispy-forms. Ändere deine Forms/Views/Templates so ab, dass crispy-forms das Rendering deiner Formulare übernimmt (insbesondere über den „crispy“-Template-Tag; nicht den „crispy“-Filter). Vergiss dabei nicht das CRISPY_TEMPLATE_PACK in deiner settings.py richtig zu setzen.

Bonusaufgabe

  1. Erstelle eine Ansicht, die tabellarisch alle Personen anzeigt, die aktuell in der Datenbank vorhanden sind. In der letzten Spalte soll ein Link zum Bearbeiten der Person vorhanden sein. Ergänze deine Ansicht der Benutzertabelle außerdem um ein Formular, um nach Benutzern mit einem bestimmten Lieblingsgetränk zu filtern.

🎉 Fertig 🎉

Noch nicht genug? Django-Crispy-Forms ist sehr mächtig und trotzdem voll anpassbar - lies dich doch etwas in die Doku zur Erstellung eigener Template-Packs ein.

(Generic)
Class-Based-Views

Was sind Class-Based-Views?

  • Klassen, die eine dispatch()-Methode anbieten
  • dispatch() wird vom URL-Dispatcher aufgerufen (wie eine View-Methode)
  • Modular + erweiterbar durch Vererbung etc.

Beispiel



            


            

Und was sind Generic Views?

  • Mitgelieferte Views, die alle Standardfälle abdecken
  • Immer Konglomerat aus Mixins + Basis-View
    • Mixins implementieren Funktionalität
    • Werden im Basis-View nur noch aufgerufen + zusammengesteckt
  • Empfehlung: Immer zuerst in Django-Doku nachsehen, ob es schon was Fertiges gibt

Beispiel BaseDetailView



            


            

Langsam wird's

richtig produktiv

Hier gehts zur Aufgabe

  1. Baue deine Views zum Anlegen/Editieren von Person-Objekten auf Class-Based-Views um. Verwende hierzu die Generic-Views, die Django schon mitliefert. Interessant ist auch das Handling bei einem erfolgreichen Speichern (also keine ValidationErrors), denn hierbei muss Django entscheiden, wohin der Anwender weitergeleitet wird. Django gibt dir bei fehlender Konfiguration Hinweise, was du tun musst!

    Im Standardfall verwendet Django die get_absolute_url()-Methode deines Models und leitet nach dem Speichern auf die dort zurückgegebene URL weiter.

  1. Ergänze in deiner „gallery“ App neue Views zum Anlegen, Bearbeiten und der Detailansicht von Fotos über CBVs. Im Anlegen- und Bearbeiten-Fall sollen alle Attribute angezeigt werden. In der Detailansicht soll das Foto recht groß inklusive des Titels angezeigt werden.

Bonusaufgabe

  1. Man soll einzelne Bilder auch löschen können - implementiere hierzu die Funktionalität inkl. einer Rückfrage, ob man sich wirklich sicher ist.

    Die Dokumentation des DeleteView könnte dir helfen!

Bonusaufgabe

  1. Aktuell lassen wir den Benutzer im Dunklen, ob das Anlegen/Bearbeiten/Löschen überhaupt funktioniert hat - das wollen wir ändern. Django bietet über das Messages-Framework eine integrierte Möglichkeit einmalige Benachrichtigungen an den Benutzer weiterzugeben, die über genau solche Sachverhalte aufklären. Implementiere entsprechende Messages beim Anlegen/Bearbeiten/Speichern. Das Basis-Template ist ein guter Platz diese Messages zu rendern. Beachte auch die Dokumentation von django-bootstrap4 in Bezug auf messages.

🎉 Fertig 🎉

Noch Zeit übrig?Kennst du noch Timsort? Entwickelt wurde der Algorithmus von Tim Peters - der zufälligerweise auch sehr aktiv an Python mitgewirkt hat. Ihm ist ein Easter-Egg in Python gewidmet. Öffne eine Python-Console und gib „import this“ ein. Sich an die Regeln zu halten ist der erste Schritt zu hervorragendem Python-Code 🐍

Django-Admin

Was bietet Django-Admin?

  • Mitgelieferte Django-App „django.contrib.admin“
  • Erzeugt automatisch Ansichten um Model-Instanzen zu erstellen/bearbeiten/löschen
  • Konfiguration ähnlich zu Forms
  • Integrierte detaillierte Benutzer- + Rechteverwaltung

With great power

comes great responsibility

Hier gehts zur Aufgabe

  1. Lege einen neuen Superuser (alle Berechtigungen) über „manage.py“ in deinem Projekt an (wie??).
  2. Logge dich in die Admin-Ansicht deiner Anwendung ein („/admin“). Aktuell kannst du nur zwei Models verwalten: User und Group. Deine selbst angelegten Models sind noch nicht für die Verwendung mit Django-Admin konfiguriert. Hole dies in den „admin.py“-Dateien deiner Anwendung nach (pro App).
  1. Lege ein neues Foto über die Admin-Ansicht an und beobachte, wie es in der Gallerieansicht auftaucht sowie über deine selbst erstellten Views bearbeitet/gelöscht werden kann. In der Admin-Ansicht gibt es sogar einen Button „View on site“, der durch die Definition deiner absolute_url am Model ermöglicht wird.
  1. Lege über die Admin-Ansicht einen neuen Benutzer an, der kein „Staff“-Benutzer ist. Versuche dich mit diesem an der Admin-Seite anzumelden.
    Gib dem Benutzer nun „Staff“ aber nicht „Superuser“. Melde dich erneut an. Was fällt dir auf?
    Du kannst feingranular steuern, was ein Benutzer/Gruppe darf - gibt dem Benutzer ausreichende Rechte, um Fotos anzulegen - sonst nichts. Wie sieht die Admin-Ansicht nun aus?
  1. Lege eine Gruppe „Photo-Admin“ an, die allumfassend Fotos administrieren darf. Gibt diese Gruppe deinem neu angelegten Benutzer. Wie sieht die Ansicht für diesen Benutzer nun aus?

🎉 Fertig 🎉

Noch Zeit übrig? Du kennst jetzt eigentlich alle Grundbausteine von Django - was würdest du sagen, dass die Grenzen von Django sind? Wann glänzt es? Schreib deine Gedanken auf - wir werden sie nachfolgend diskutieren!

Django-REST-Framework

Django-REST-Framework

  • Dritt-Django-App
  • Erzeugt vollautomatisch eine CRUD-REST-API zu Models
  • Sogar Views zum Erforschen im Browser
  • Perfekt um Django als Backend für JS/Mobile-App zu verwenden

Beispiel: Photo Model



            


            

Ergebnis

🎉 Geschafft! 🎉

Vielen Dank für deine Teilnahme

Du hast immer noch nicht genug? Schon mal was von Phoenix-LiveView gehört? Sowas ähnliches gibt's für Django auch: Django Sockpuppet. Kombiniere das noch mit Alpine.js und du hast Anwendungen, die sich anfühlen wie React/Vue.js aber nur mit ⅓ der Arbeit. Das glaubst du nicht? Probier es doch aus - das Rüstzeug hast du jetzt!
😄

Diskussion 🕵

Grenzen / Glanzpunkte Django