Django-Superkraft: Eine CRUD-Web-App in 60 Minuten

Teil 2: Erstellen des Front-End

  • 19. September 2020

Eine der Stärken von Django ist, dass man schnell zu präsentierbaren Ergebnissen gelangt. In diesem zweiteiligen Tutorial zeige ich auf, wie man in knapp 60 Minuten eine CRUD-App erstellt. Im ersten Teil haben wir das Projekt installiert und konfiguriert, die App initialisiert, die Datenbankmodelle hinzugefügt und mit dem Django-Admin verknüpft. In diesem Teil des Tutorials werden wir ein Front-End hinzufügen, das alle vier CRUD-Operationen unterstützt, plus eine Listenansicht der Datenbankeinträge.

Von den sieben Schritten, die Grundsätzlich nötig sind, um eine Web-App in Django zu erstellen, haben wir die ersten vier im vorangehenden Artikel gemeistert. Wenn du Teil 1 noch nicht durchgearbeitet hast, empfehle ich dir, dies jetzt zu tun und dann hierher zurückzukehren. Hier nochmals die sieben Schritte.

  1. Installation
  2. Konfiguration
  3. Erstellen der Datenbank-API
  4. Konfiguration des Django-Admins (optional)
  5. Erstellen der URLs
  6. Erstellen der Views
  7. Erstellen der Templates

Die Schritte 5 bis 7 sind der Inhalt dieses Teils des Tutorials. Wir werden diese iterativ durchgehen, d.H. für jede CRUD-Funktion werden wir zuerst eine URL, dann einen View und ein Template erstellen. Im gesamten werden wir so fünf Mal diesen 3-stufigen Zyklus durchlaufen.

Bevor wir die eigentlichen CRUD-Funktionen angehen, legen wir das Basis-Template des Projektes an und lassen die Homepage auf die App adressen zeigen. Let’s go!

Basis-Template und Projekt-URL definieren

Im ersten Teil haben wir unter Punkt 2. Konfiguration, das Projekt so konfiguriert, dass HTML-Templates projektweit eingesetzt werden können und nicht auf die jeweilige App beschränkt sind. Dies nutzen wir für die Erstellung eines Basis-Templates, in dem wir die Grundstruktur festlegen, die für alle Webseiten unseres Projektes gilt. Dazu zählen das CSS und die Verweise auf externe Ressourcen, wie das CSS-Framework Bootstrap.

Erstellen des Basis-Templates

Lege dazu im Verzeichnis templates, auf der Ebene von manage.py ein leeres Dokument namens base.html an.

Stelle sicher, dass du dich in der Kommandozeile auf der Hauptebene des Projektes befindest. Dies tust du, in dem du mit dem Kommando pwd das aktuelle Verzeichnis anzeigst:

pwd

Die Ausgabe des Terminals sollte ungefähr so aussehen:

didier@computer ~/Dokumente/django_crud_app/meinprojekt $

Wenn die virtuelle Umgebung nicht bereits aktiviert ist – du erkennst das am (env) am Beginn der Textzeile – dann tu dies jetzt:

# Mac & Linux
source env/bin/activate

# Windows Powershell
env/Scripts/activate

Am Anfang der Zeile wird jetzt ein (env) in Klammern angezeigt:

(env) didier@computer ~/Dokumente/django_crud_app/meinprojekt $

Erstelle die Datei base.html:

# Mac & Linux
touch templates/base.html

# Windows Powershell
New-Item templates/base.html

Deine Ordnerstruktur sieht jetzt so aus:

meinprojekt ├── adressen │ ├── (...) │ └── (...) ├── db.sqlite3 ├── manage.py ├── meinprojekt │ ├── (...) │ └── (...) └── templates └── base.html # Neu

Öffne die neue Datei base.html und füge diesen Code ein:

<!DOCTYPE html>
<html>
  <head>
    <title>Mein Projekt</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  </head>
  <body>
    <div class="container-fluid">
        <header>
            <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
                <a class="navbar-brand" href="{% url 'adress_start' %}">Django Superkraft</a>
            </nav>
        </header>
        <div class="jumbotron">
            <h1>Ein CRUD-Projekt in 60 Minuten</h1>
            <h2>Eine einfache Adressbuch-App</h2>
        </div>
        {% block content %}
        {% endblock content %}
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
  </body>
</html>

Für die Gestaltung werden wir das CSS-Framework Bootstrap einsetzen, was den grössten Teil des obigen Codes ausmacht. Damit erreichen wir, dass unsere Web-App mit wenig Aufwand von Anfang an optisch etwas hermacht. Das ist vor allem nützlich, wenn du das Projekt jemandem präsentierst, der keine Ahnung von Programmieren hat, also Eltern, Freunden, dem Chef oder Kunden. Denn eine App, die gut aussieht, macht mehr Eindruck.

Die einzelnen Teile des Templates im Überblick: Im head-Element importieren wir die CSS-Dateien des Bootstrap-Framework per CDN (Content Delivery Network). Dann setzen wir im HTML-body-Element einen header mit einem nav-Element für die Navigation und danach ein Bootstrap Jumbotron. Dieses kann man sich wie eine Reklametafel vorstellen, und wir nutzen es auch so um, unser Projekt ansprechend zu präsentieren. Vor dem schliessenden body-Element schliesslich importieren wir nochmals per CDN drei JavaScript-Files, die von Bootstrap benötigt werden. Als Erstes die JQuery-Bibliothek, dann Popper.js und am Schluss die JavaScript-Dateien von Bootstrap.

Das wichtigste Element in diesem Template habe ich bis jetzt vorgehalten. Unter dem Jumbotron hast du sicher folgende Struktur bemerkt:

{% block content %}
{% endblock content %}

Das ist ein so genanntes Django Template-Tag, und zwar ein Block-Element. Dieses ermöglicht uns, die anderen Templates aus dem Projekt in das base.html-Template zu laden. Damit können wir die Grundstruktur des Projektes (Header, Footer und Elemente wie CSS und JavaScript) einmal definieren, ohne dies in jedem einzelnen Template tun zu müssen. Diese Tags verhalten sich wie Container in die wir andere Templates hinein laden.

URL-Verweis auf die App anlegen

Damit Django die HTTP-Anfragen (HTTP-Requests) aus dem Browser an die App weiterleiten kann, müssen wir im URL-Verzeichnis unseres Projektes den Verweis dazu festlegen. Öffne die Datei meinprojekt/urls.py und füge zwei Zeilen hinzu:

# meinprojekt/urls.py

from django.contrib import admin
from django.urls import path
from django.urls import include # Neu

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('adressen.urls')), # Neu
]

Mit dem Import der Funktion include ermöglichen wir den direkten Verweis auf ein anderes URL-Verzeichnis, in diesem Falle, dasjenige der App adressen, also adressen/urls.py. Mit dem leeren String '' als erstes Argument bewirken wir, dass alle Anfragen an http://127.0.0.1:8000/ sofort an das URL-Verzeichnis unserer App weitergeleitet werden. Dort findet dann die weitere Verarbeitung statt.

L wie L in CRUDL: Erstellen der Listenübersicht

Beginnen wir endlich :-) mit der eigentlichen CRUD-App! Zuerst erstellen wir einen ListView, mit dem wir eine Listenansicht aller Adressbucheinträge anzeigen. Dies wird bisweilen als Erweiterung von CRUD gesehen und ist vor allem in der Web-Entwicklung immer wieder nützlich um eine Liste von Elementen aus der Datenbank anzuzeigen. Das entsprechende Akronym dafür ist CRUDL.

Erstellen der URL

Zuerst erstellen wir eine URL für unsere Listenübersicht, welche gleichzeitig als Startseite für die App dient. Eine URL ist wie ein Wegweiser innerhalb eines Django-Projektes. Mittels einer URL teilen wir Django mit, was als Nächstes passieren soll. Eine URL ist die Zeichenkette die wir im Browser in die Adressleiste eingeben. Z. B. www.google.ch oder https://www.djangoblog.ch/de/django/was-ist-django/. Diese URLs sind uns so vertraut, dass wir nicht viele Gedanken darauf verwenden, tatsächlich stellen sie die wichtigste Logik innerhalb einer Web-App und allgemein einer Webseite dar. Sie sind es, die bestimmen, welche Seite als Nächstes aufgerufen wird.

Für unsere erste URL müssen wir zuerst im Ordner adressen die Datei urls.py erstellen:

# Mac & Linux
touch adressen/urls.py

# Windows Powershell
New-Item adressen/urls.py

Und füge folgenden Code ein:

# adressen/urls.py

from django.urls import path
from .views import AdressHome

urlpatterns = [
     path('', AdressHome.as_view(), name='adress_start'),
]

In der ersten Zeile importieren wir die Methode path aus dem urls-Modul. Dann importieren wir aus dem Modul views.py den noch nicht erstellten AdressHome-View. In der urlpatterns-Liste fangen wir mit der leeren Zeichenkette '' alle Anfragen mit dem Muster http://127.0.0.1:8000/ und leiten sie an den View AdressHome weiter. Da dieser View ein klassenbasierter View sein wird, müssen wir ihn mit dem Argument .as_view() aufrufen. Als Letztes geben wir der URL einen Namen: name='adress_start'. Damit können wir von überall her (was vor allem in Templates nützlich ist) auf die URL zugreifen.

Erstellen des View

Legen wir jetzt den View AdressHome an. Was ist ein View? Ein View ist eine Seite einer Web-App, beherbergt die Logik eines Aufrufs und bestimmt damit, was auf einer Seite angezeigt wird. Ein View hat meistens ein Template. In diesem Fall ist der View AdressHome dafür zuständig, alle Adresseinträge aus der Datenbank abzurufen (Read) und dann an das Template zu übergeben, welches wir im Anschluss an den View anlegen werden. Öffne die Datei views.py aus dem Ordner adressen und füge folgenden Code ein:

# adressen/views.py

from django.shortcuts import render

from django.views.generic import ListView # Neu

from .models import Adressen # Neu

class AdressHome(ListView): # Neu
    model = Adressen # Neu
    template_name = 'adressen/adress_home.html' # Neu

Mit dem Import from django.views.generic import ListView laden wir die Klasse ListView aus dem views-Modul von Django. Davon leiten wir unsere eigene Klasse class AdressHome(ListView) ab. Wir müssen dann nur noch die spezifischen Informationen überschreiben. Das tun wir, indem wir das Attribut model mit unserem Datenbankmodell Adressen definieren, welches wir oben importiert haben. Als Template weisen wir dem Attribut template_name unser noch zu erstellendes Template adress_home.html zu.

Erstellen des Templates

Die Templates für die Adress-App legen wir in der App ab. Es bestände die Möglichkeit, die Templates in den Haupt-Template-Ordner, den wir im ersten Teil erstellt haben, abzulegen. Das wird in manchen Tutorials so gehandhabt. Wenn du sicher bist, dass du die App später nicht in einem anderen Projekt verwenden wirst, kann das eine gute Idee sein. Wenn wir unsere App portabel halten wollen, empfiehlt es sich, die App-spezifischen Templates in der App abzulegen und diese möglichst rudimentär zu halten, d.H. auf die Logik zu reduzieren ohne Gestaltungselemente, etc.

Damit Django diese Templates findet, muss in settings.py folgende Einstellung gesetzt sein:

# meinprojekt/settings.py

(...)

TEMPLATES = [
    {
        (...)
        'APP_DIRS': True,
        (...)
    },
]

(...)

Das ist die Grundeinstellung, überprüfe dennoch kurz, ob das bei dir so eingestellt ist.

Da Django die Templates immer aus einem Ordner mit dem Namen templates lädt, legen wir diesen Ordner jetzt an:

mkdir adressen/templates

Innerhalb dieses Ordners legen wir einen zweiten Ordner an, der gleich heisst wie unsere App, das nennt sich namespacing und erstellt einen Namensraum, mit dessen Hilfe Django weiss, aus welchem Ordner die Templates geladen werden müssen. Tippe:

mkdir adressen/templates/adressen

In diesen verschachtelten Ordner erstellen wir die Datei adress_home.html:

# Mac & Linux
touch adressen/templates/adressen/adress_home.html

# Windows Powershell
New-Item adressen/templates/adressen/adress_home.html

Und befülle sie mit folgendem Inhalt:

<!-- adressen/templates/adressen/adress_home.html -->

{% extends 'base.html' %}

{% block content %}
<h2>Alle Adressen</h2>
<ul>
    {% for adresse in object_list %}
    <li><a href="#">{{ adresse.vorname }} {{ adresse.nachname }}</a></li>
    {% endfor %}
</ul>
<a class="btn btn-success btn-sm" href="#">+ Neue Adresse hinzufügen</a>
{% endblock content %}

Gehen wir Schritt für Schritt durch das Template: Mit {% extends 'base.html' %} sagen wir Django, dass dieses Template eine Erweiterung unseres Haupt-Templates base.html im Ordner meinprojekt/templates ist. Der nächste Abschnitt {% block content %} wird somit vollständig in den gleichnamigen Block des Haupttemplates geladen.

Es folgt ein Titel und ein Listenelement. Innerhalb des UL-Elements setzen wir ein for-Loop, mit dem wir die in unserem View aus der Datenbank geholten Objekte nacheinander abfragen und untereinander als HTML-Liste darstellen.

{% for adresse in object_list %}
    <li><a href="#">{{ adresse.vorname }} {{ adresse.nachname }}</a></li>
{% endfor %}

Als Nächstes definieren wir einen Button zum Hinzufügen einer neuen Adresse:

<a class="btn btn-success btn-sm" href="#">+ Neue Adresse hinzufügen</a>

Unser erster View ist bis auf die Links in den einzelnen Einträgen und dem Button fertig. Die Links werden wir hinzufügen, sobald wir alle URLs und Views fertiggestellt haben.

Starte jetzt den Django runserver:

python manage.py runserver

Und navigiere zu folgender URL: http://127.0.0.1:8000/

Du solltest folgende Webseite sehen:

Was passiert im Hintergrund, wenn wir im Browser die URL http://127.0.0.1:8000/ eingeben? Der Webserver erhält diese Anfrage von unserem Browser und sendet sie weiter an Django, wo sie an die Datei meinprojekt/urls.py (den so genannten URL-Resolver) gesendet wird. Diese Datei ist die erste Anlaufstelle für alle eingehenden URL-Anfragen. Der Domain-Name, hier 127.0.0.1:8000/ wird abgeschnitten. Der übrig bleibende Wert, in diesem Falle eine leere Zeichenkette (kein Zeichen nach dem Schrägstrich wird als leere Zeichenkette interpretiert) wird durch die urlpatterns-Liste gejagt und dabei nach einer Übereinstimmung gesucht. Diese wird in diesem Falle im zweiten Wert (path('', include('adressen.urls')) gefunden. Django sendet diese Anfrage jetzt gemäss der include-Anweisung weiter an unsere Adress-App und deren URL-Datei. Dort durchläuft der übrig gebliebene Wert wiederum die urlpatterns-Liste in der Datei adressen/urls.py, bis ein übereinstimmender Wert gefunden wird. Dies geschieht im folgenden Muster path('', AdressHome.as_view(), name='adress_start'). Hier wird Django angewiesen, bei einer Übereinstimmung den View AdressHome aufzurufen. Dieser ist dafür zuständig, eine Liste aller in der Datenbank befindlichen Adressen abzurufen und an das Template adress_home.html zu senden. Das for-Loop im Template, {% for adresse in object_list %}, durchläuft alle Objekte und wandelt dabei jedes Einzelne in HTML um und gibt es auf dem Bildschirm aus.

C wie in Create: Erstellen des Create-View

Kommen wir zu unserem ersten CRUD-View und erstellen den Code für das Anlegen einer neuen Adresse im Front-End.

Erstellen der URL für den Create-View

Beende mit Ctrl + C (Mac und Linux) oder Ctrl + Pause (Windows) den Django runserver. Öffne die Datei adressen/urls.py und ergänze sie mit folgendem Code (gekennzeichnet mit # Neu):

# adressen/urls.py

from django.urls import path
from .views import AdressHome
from .views import AdressCreate # Neu

urlpatterns = [
    path('', AdressHome.as_view(), name='adress_start'),
    path('neu/', AdressCreate.as_view(), name='neue_adresse'), # Neu
]

Zu diesem Code gibt es nichts Neues zu sagen, so dass wir direkt zum View übergehen.

Erstellen des View für den Create-View

Um den View zu erstellen öffne die Datei adressen/views.py und ergänze sie mit folgendem Code (gekennzeichnet mit # Neu):

# adressen/views.py

from django.shortcuts import render
from django.urls import reverse_lazy # Neu
from django.views.generic import ListView
from django.views.generic import CreateView # Neu

from .models import Adressen

class AdressHome(ListView):
(...)


class AdressCreate(CreateView): # Neu
    model = Adressen # Neu
    template_name = 'adressen/adress_create.html' # Neu
    fields = '__all__' # Neu
    success_url = reverse_lazy('adress_start') # Neu

Als Erstes importieren wir die Funktion reverse_lazy, mit der wir auf eine benannte URL verweisen. Im Gegensatz zu reverse wartet reverse_lazy, bis der Datenbank-Eintrag fertig angelegt ist. Danach importieren wir den CreateView aus der Klasse views.generic und leiten dann unsere Klasse AdressCreate(CreateView) davon ab. Wir definieren das Datenbankmodell und das Template und setzen das Attribut fields auf den  Wert '__all__' um Django anzuzeigen, dass wir in dieser Klasse alle Felder der Model-Klasse verwenden. Ausserdem definieren wir mit dem Attribut success_url eine URL, auf die der Benutzer weitergeleitet wird, sobald der Datenbankeintrag angelegt ist. In diesem Falle zurück auf die Startseite. Dort wird der neue Eintrag dann auch gleich angezeigt.

Erstellen des Templates

Für einen fertigen View fehlt jetzt noch das Template. Legen wir dieses an:

# Mac & Linux
touch adressen/templates/adressen/adress_create.html

# Windows Powershell
New-Item adressen/templates/adressen/adress_create.html

Und füge folgenden Code ein:

<!-- adressen/templates/adressen/adress_create.html -->

{% extends 'base.html' %}

{% block content %}
<h2>Neue Adresse hinzufügen</h2>
<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <a class="btn btn-danger btn-sm" href="{% url 'adress_start' %}">Abbrechen</a>
    <button type="reset" class="btn btn-secondary btn-sm">Zurücksetzen</button>
    <button type="submit" class="btn btn-success btn-sm">Speichern</button>
</form>
{% endblock content %}

Wir importieren dieses Template in der Anweisung {% extends 'base.html' %} als Erweiterung von base.html und definieren Folgendes im {% block content %}:

  • Ein Titel <h2>
  • Ein Formular <form> mit der Methode post
  • Dann setzen wir mit dem Tag {% csrf_token %} ein Sicherheitselement ein. Mit diesem Tag wird verhindert, dass Schadcode dein Formular per Cross-Site-Request-Forgery missbrauchen kann.
  • Darunter setzen wir die Variable {{ form.as_p }}. Damit erweitert Django alle Felder eines Formulars zu HTML-Input-Feldern und stellt sie jeweils in ein <p>-Tag.
  • Jetzt folgen drei Buttons: Abbrechen als <a>-Tag, Zurücksetzen des Formulars als type="reset" und Speichern als type="submit"

Das wäre es für den CreateView. Testen wir jetzt den View und starten den Django runserver:

python manage.py runserver

Gehe zu http://127.0.0.1:8000/neu/. Du solltest Folgendes sehen: 

Erstelle hier eine neue Adresse, in dem du die Felder ausfüllst. In diesem Formular sind alle Felder Pflichtfelder, da der CreateView alle Angaben direkt aus unserem Datenbankmodell ableitet und wir dort die Felder so definiert haben. Beim Klick auf Speichern wird der neue Datensatz in der Datenbank gespeichert und wir werden auf die Homepage unserer Adress-App zurückgeleitet. Dort siehst du jetzt die neue Adresse (Daniel Düsentrieb) ganz unten.

Template vervollständigen

Wenn du auf den grünen Button Neue Adresse hinzufügen klickst, wird nichts passieren. Dies deshalb, weil wir die URL noch nicht festgelegt haben. Da wir mittlerweile den CreateView erstellt haben, auf den wir mit diesem Button verweisen, können wir den Link erstellen ohne das Django eine Fehlermeldung ausgibt. Beende den Django runserver und öffne das Template adressen/templates/adressen/adress_home.html und ändere folgende Zeile:

<!-- adressen/templates/adressen/adress_home.html -->

<a class="btn btn-success btn-sm" href="#">+ Neue Adresse hinzufügen</a>

Zu:

<!-- adressen/templates/adressen/adress_home.html -->

<a class="btn btn-success btn-sm" href="{% url 'neue_adresse' %}">+ neue Adresse hinzufügen</a>

Starte nochmals den Django runserver. Beim Klick auf den grünen Button wirst du jetzt zum Formular des CreateView weitergeleitet.

R wie Read: Erstellen des Detail-View

Kommen wir zum nächsten Buchstaben in unserem Akronym: zu R wie Read. Als Read-Funktion werden wir einen DetailView einsetzen, der dafür zuständig ist, uns eine einzelne Adresse anzuzeigen. Beginnen wir auch hier mit der URL.

Erstellen der URL

Beende den Django runserver öffne die Datei adressen/urls.py und füge folgenden Code hinzu (gekennzeichnet mit # Neu):

# adressen/urls.py

(...)
from .views import AdressCreate
from .views import AdressDetail # Neu

urlpatterns = [     
    (...)
    (...)
    path('<int:pk>/', AdressDetail.as_view(), name='adress_detail'), # Neu
]

Erstellen des View

Öffne als Nächstes die Datei adressen/views.py und ergänze sie mit folgendem Code (gekennzeichnet mit # Neu):

# adressen/views.py

(...)
from django.views.generic import CreateView
from django.views.generic import DetailView # Neu

(...)

class AdressCreate(CreateView):
(...)


class AdressDetail(DetailView): # Neu
    model = Adressen # Neu
    template_name = 'adressen/adress_detail.html' # Neu

Dieser View benötigt ebenfalls ein eigenes Template: adressen/adress_detail.html. Legen wir dies an.

Erstellen des Templates

Erstelle eine leere Datei:

# Mac & Linux
touch adressen/templates/adressen/adress_detail.html

# Windows Powershell
New-Item adressen/templates/adressen/adress_detail.html

Und füge folgenden Code ein:

<!-- adressen/templates/adressen/adress_detail.html -->

{% extends 'base.html' %}

{% block content %}
    <h2>Adressdetail</h2>
    <p>Vorname: {{adressen.vorname }}</p>
    <p>Name: {{adressen.nachname }}</p>
    <p>Strasse: {{adressen.strasse}}</p>
    <p>PLZ: {{adressen.plz}}</p>
    <p>Ort: {{adressen.ort}}</p>
    <a class="btn btn-secondary btn-sm" href="{% url 'adress_start' %}">Zurück</a>
    <a class="btn btn-danger btn-sm" href="#">Löschen</a>
    <a class="btn btn-success btn-sm" href="#">Update</a>
{% endblock content %}

Auch dieses Template erweitern wir wieder innerhalb unseres base.html Templates mit {% extends 'base.html' %} und rendern den Inhalt innerhalb des Blocks {% block content %}. Dann setzen wir einen Titel (h2) und holen uns danach die verschiedenen Datenbankfelder des aktuellen Objekts in das Template. Dies machen wir mit der Punkt-Schreibweise. Dazu schreiben wir den Namen des Objektes in Kleinbuchstaben, hier adressen (das Datenbankmodell heisst Adressen), setzen danach einen Punkt und schreiben dann den Namen des gewünschten Feldes. Also so: {{ objekt.datenbankfeld }}.

Danach setzen wir drei Buttons, diesmal alle als <a>-Tag. Bei Löschen und Update lassen wir die Links leer, und werden diese hinzufügen, sobald alle URLs definiert sind.

Damit wir von der Startseite als Benutzer mit einem Klick auf die Detailansicht gelangen, ersetzen wir jetzt im Template adressen/templates/adressen/adress_home.html den Platzhalter # mit der richtigen URL. Öffne das Template und ersetze folgenden Code:

<!-- adressen/templates/adressen/adress_home.html -->

<li><a href="#">{{ adresse.vorname }} {{ adresse.nachname }}</a></li>

Mit dieser Zeile:

<!-- adressen/templates/adressen/adress_home.html -->

<li><a href="{% url 'adress_detail' adresse.pk %}">{{ adresse.vorname }} {{ adresse.nachname }}</a></li>

Mit dem Template-Tag {% url 'adress_detail' adresse.pk %} setzen wir für jedes Objekt innerhalb des for-Loops einen spezifischen Link auf das Objekt. Der entscheidende Punkt dabei ist adresse.pk, damit verweisen wir auf den PrimaryKey jedes einzelnen Objektes. Der PrimaryKey ist die eindeutige Identität eines Objektes in der Datenbank.

Testen wir unseren DetailView. Starte dazu wieder den Django runserver:

python manage.py runserver

Und rufe die Webseite auf: http://127.0.0.1:8000/. Klicke jetzt auf einen der angezeigten Adressen auf der Homepage.

Du wirst dann auf die folgende Detailseite weitergeleitet:

Die URL oben im Browserfenster sieht bei mir so aus: http://127.0.0.1:8000/1/. Die 1 hinter dem 8000/ bezeichnet in diesem Fall den PrimaryKey der Adresse Micky Mouse und ist deren eindeutige Identität in der Datenbank.

Erstellen des Update-View

Damit haben wir zwei der wichtigsten Views einer Front-End App erstellt. Um die bestehende Adresse zu aktualisieren (update) müssen wir einen neuen View erstellen: den UpdateView. Beginnen wir wieder mit der URL.

Erstellen der URL

Öffne dazu die urls.py Datei unserer App adressen und füge folgenden Code hinzu (gekennzeichnet mit # Neu):

<!-- adressen/urls.py -->

(...)
from .views import AdressDetail
from .views import AdressUpdate # Neu

urlpatterns = [
    (...)
    path('<int:pk>/', AdressDetail.as_view(), name='adress_detail'),
    path('<int:pk>/update/', AdressUpdate.as_view(), name='adress_update'), # Neu
]

Erstellen des View

Öffne jetzt die Datei adressen/views.py und füge unten stehenden Code hinzu (gekennzeichnet mit # Neu):

# adressen/views.py

(...)
from django.views.generic import DetailView
from django.views.generic import UpdateView # Neu

(...)


class Adress Detail(DetailView):
(...)


class AdressUpdate(UpdateView): # Neu
    model = Adressen # Neu
    template_name = 'adressen/adress_update.html' # Neu
    fields = '__all__' # Neu

Erstellen des Templates

Erstelle die Datei adressen/templates/adressen/adress_update.html:

# Mac & Linux
touch adressen/templates/adressen/adress_update.html

# Windows Powershell
New-Item adressen/templates/adressen/adress_update.html

Öffne die Datei und füge folgenden Code ein:

<!-- adressen/templates/adressen/adress_update.html -->

{% extends 'base.html' %}

{% block content %}
<h2>Neue Adresse bearbeiten</h2>
<form action="" method="post">{% csrf_token %}
    {{ form.as_p }}
    <a class="btn btn-danger btn-sm" href="{% url 'adress_start' %}">Abbrechen</a>
    <button type="reset" class="btn btn-secondary btn-sm">Zurücksetzen</button>
    <button type="submit" class="btn btn-success btn-sm">Speichern</button>
</form>
{% endblock content %}

Wir sind mit dem Update View soweit fertig. Im DetailView fehlt noch der Link im Button Update. Öffne das Template adressen/templates/adressen/adress_detail.html und ersetze folgende Zeile:

<!-- adressen/templates/adressen/adress_detail.html -->

<a class="btn btn-success btn-sm" href="#">Update</a>

Mit:

<!-- adressen/templates/adressen/adress_detail.html -->

<a class="btn btn-success btn-sm" href="{% url 'adress_update' adressen.pk %}">Update</a>

Das wär‘s. Starte den Django runserver:

python manage.py runserver

Und sieh dir das Ergebnis an. Klicke dazu auf der Hauptseite auf eine der Adressen und klicke dann in der Detailansicht auf den grünen Button Update:

Du wirst sofort zum Eingabe-Formular des Update-View weitergeleitet.

Die drei Buttons haben folgende Aufgaben:

  • Abbrechen = zurück zur Startseite
  • Zurücksetzen = setzt alle aktuellen Änderungen auf den zuerst angezeigten Wert zurück.
  • Speichern = speichert die Änderungen in der Datenbank und bringt dich zurück zum DetailView.

Wir sind fast fertig. Es bleibt nur noch ein View übrig.

D wie Delete: Erstellen des Delete-View

Wir haben nun schon einiges an Übung und können den vierten Durchgang ohne weitere Erklärungen abarbeiten.

Erstellen der URL

Öffne die Datei adressen/urls.py und füge folgenden Code ein (gekennzeichnet mit # Neu):

# adressen/urls.py

(...)
from .views import AdressUpdate
from .views import AdressDelete # Neu

urlpatterns = [
    (...)
    path('<int:pk>/update/', AdressUpdate.as_view(), name='adress_update'),
    path('<int:pk>/delete/', AdressDelete.as_view(), name='adress_delete'), # Neu
]

Erstellen des Views

Öffne die Datei adressen/views.py und füge folgenden Code hinzu (gekennzeichnet mit # Neu):

# adressen/views.py

(...)
from django.views.generic import UpdateView
from django.views.generic import DeleteView # Neu

(...)


class AdressUpdate(UpdateView):
(...)


class AdressDelete(DeleteView): # Neu
    model = Adressen # Neu
    template_name = 'adressen/adress_delete.html' # Neu
    success_url = reverse_lazy('adress_start') # Neu

Erstellen des Templates

Erstelle die Datei adressen/templates/adressen/adress_delete.html:

# Mac & Linux
touch adressen/templates/adressen/adress_delete.html

# Windows Powershell
New-Item adressen/templates/adressen/adress_delete.html

Und füge folgenden Code ein:

<!-- adressen/templates/adressen/adress_delete.html -->

{% extends 'base.html' %}

{% block content %}
<h2>Adresse löschen</h2>
<form action="" method="post">{% csrf_token %}
    <p>Bist du sicher das du folgende Adresse löschen möchtest?</p>
    <p><strong>{{ adressen.vorname }} {{ adressen.nachname }}</strong></p>
    <a class="btn btn-secondary btn-sm" href="{% url 'adress_detail' adressen.pk %}">Zurück</a>
    <button type="submit btn-sm" class="btn btn-danger btn-sm">Löschen</button>
</form>
{% endblock content %}

Auch hier müssen wir den fehlenden Link in unseren DetailView einbauen. Öffne das Template adressen/templates/adressen/adress_detail.html und ersetze folgende Zeile:

<!-- adressen/templates/adressen/adress_detail.html -->

<a class="btn btn-danger btn-sm" href="#">Löschen</a>

Mit:

<!-- adressen/templates/adressen/adress_detail.html -->

<a class="btn btn-danger btn-sm" href="{% url 'adress_delete' adressen.pk %}">Löschen</a>

Starte den Django runserver und navigiere zu einer Detail-Ansicht einer Adresse:

Klicke auf den Button Löschen und folgende Seite wird angezeigt:

Klicke nochmals auf Löschen, um den Vorgang zu bestätigen, und du wirst auf die Homepage zurückgeleitet. Die Adresse ist jetzt aus unserer Datenbank gelöscht und wird in der Liste aller Adressen nicht mehr aufgeführt.

Zusammenfassung

Damit haben wir eine voll funktionsfähige Web-App mit den vier Grundfunktionen eines datenbankgetriebenen Programms erstellt und sind damit am Ende des Tutorials angelangt. Nebenbei gab es einen Einblick in den äusserst nützlichen Django-Admin, der die Entwicklung eines Projektes ungemein erleichtert.

Das könnte dich auch interessieren

Django-Superkraft: Eine CRUD-Web-App in 60 Minuten

Teil 1: Installation und Konfiguration

  • 17. Juli 2020

Eine der Stärken von Django ist, dass man schnell zu präsentierbaren Ergebnissen gelangt. Ein Beispiel dafür ist die Arbeit mit einer Datenbank, was für eine moderne Web-App zentral ist. Bei vielen Systemen besteht die Herausforderung darin, zuerst die aufwendige Konfiguration des Datenbanksystems und der API richtig hinzubekommen, bevor überhaupt mit der Programmierung der Web-App begonnen werden kann. Nicht so in Django. Die Anbindung an eine Datenbank ist ein Kinderspiel. Dies zeige ich am Beispiel dieses Tutorials, in dem wir eine voll funktionsfähige Web-App mit Datenbankanbindung erstellen.

Erstellen eines Django-Projektes

  • 30. Januar 2021

Ein Django-Projekt zu erstellen ist nicht schwer und schnell erledigt. Dennoch besteht die Installation aus mehreren Schritten. In diesem Blog-Post habe ich diese festgehalten. Auf diese Weise kann ich ein neues Projekt schnell aufsetzen und mit der Arbeit an der eigentlichen Idee beginnen.

Statische Dateien mit Django verwalten

  • 12. Januar 2022

Statische Dateien wie CSS Stylesheets, JavaScript Code, Logos und Bilder sind ein wichtiger Bestandteil jeder Webseite. Django-Projekte sind da keine Ausnahme. Das Web-Framework bietet dem Entwickler flexible Möglichkeiten, statische Dateien in kleinen und grossen Projekten zu verwalten. In dieser Anleitung zeige ich auf, wie die Grundkonfiguration aussieht, was jeweils dahintersteckt und was beachtet werden muss.