Einführung
Dieser Tutorial beginnt dort, wo Set Up the Database aufgehört hat. Wir setzen die Web-Umfrageanwendung fort und werden uns auf die Erstellung der öffentlichen Schnittstelle - den "Views" - konzentrieren.
💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken
Dieser Tutorial beginnt dort, wo Set Up the Database aufgehört hat. Wir setzen die Web-Umfrageanwendung fort und werden uns auf die Erstellung der öffentlichen Schnittstelle - den "Views" - konzentrieren.
Eine Ansicht ist eine "Art" von Webseite in Ihrer Django-Anwendung, die im Allgemeinen eine bestimmte Funktion erfüllt und eine bestimmte Vorlage hat. Beispielsweise könnte eine Blog-Anwendung die folgenden Ansichten haben:
In unserer Umfrageanwendung werden wir die folgenden vier Ansichten haben:
In Django werden Webseiten und anderer Inhalt durch Ansichten bereitgestellt. Jede Ansicht wird durch eine Python-Funktion (oder Methode, im Falle von klassenbasierten Ansichten) repräsentiert. Django wird eine Ansicht auswählen, indem es die angeforderte URL untersucht (genauer gesagt den Teil der URL nach dem Domainnamen).
In Ihrer Zeit im Internet haben Sie möglicherweise solche Schönheiten wie ME2/Sites/dirmod.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B
kennen gelernt. Sie werden sich freuen zu hören, dass Django uns viel elegantere URL-Muster als das erlaubt.
Ein URL-Muster ist die allgemeine Form einer URL - beispielsweise: /newsarchive/<year>/<month>/.
Um von einer URL zu einer Ansicht zu gelangen, verwendet Django sogenannte 'URL-Konfigurationen'. Eine URL-Konfiguration bildet URL-Muster auf Ansichten ab.
Dieser Tutorial bietet grundlegende Anweisungen zur Verwendung von URL-Konfigurationen, und Sie können sich auf /topics/http/urls
für weitere Informationen beziehen.
Fügen wir nun einige weitere Ansichten zu polls/views.py
hinzu. Diese Ansichten unterscheiden sich etwas, da sie ein Argument entgegennehmen:
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
Verknüpfen Sie diese neuen Ansichten mit dem polls.urls
-Modul, indem Sie die folgenden ~django.urls.path
-Aufrufe hinzufügen:
Bearbeiten Sie die Datei polls/urls.py
und fügen Sie die folgenden Zeilen hinzu:
from django.urls import path
from. import views
urlpatterns = [
## ex: /polls/
path("", views.index, name="index"),
## ex: /polls/5/
path("<int:question_id>/", views.detail, name="detail"),
## ex: /polls/5/results/
path("<int:question_id>/results/", views.results, name="results"),
## ex: /polls/5/vote/
path("<int:question_id>/vote/", views.vote, name="vote"),
]
Führen Sie nun den Server erneut aus:
cd ~/project/mysite
python manage.py runserver 0.0.0.0:8080
Wechseln Sie zur Registerkarte Web 8080 bei /polls/34/
. Es wird die detail()
-Methode ausgeführt und das in der URL angegebene ID angezeigt. Versuchen Sie auch /polls/34/results/
und /polls/34/vote/
- diese werden die Platzhalter-Resultate und Abstimmungsseiten anzeigen.
Wenn jemand eine Seite von Ihrer Website anfordert - sagen wir /polls/34/
, lädt Django das Python-Modul mysite.urls
, da es durch die Einstellung ROOT_URLCONF
angegeben ist. Es findet die Variable urlpatterns
und läuft die Muster in der angegebenen Reihenfolge durch. Nachdem es die Übereinstimmung bei 'polls/'
gefunden hat, entfernt es den übereinstimmenden Text ("polls/"
) und sendet den verbleibenden Text - "34/"
- an die URL-Konfiguration von 'polls.urls'
für weitere Verarbeitung. Dort stimmt es mit '<int:question_id>/'
überein, was zu einem Aufruf der detail()
-Ansicht wie folgt führt:
detail(request=<HttpRequest object>, question_id=34)
Der Teil question_id=34
stammt aus <int:question_id>
. Mit Hilfe von spitzen Klammern "fangt" man einen Teil der URL und sendet ihn als Schlüsselwortargument an die Ansichtsfunktion. Der Teil question_id
der Zeichenfolge definiert den Namen, der verwendet wird, um das übereinstimmende Muster zu identifizieren, und der Teil int
ist ein Konverter, der bestimmt, welche Muster diesem Teil des URL-Pfads entsprechen sollten. Das Doppelpunktzeichen (:
) trennt den Konverter und den Muster-Namen voneinander.
Jede Ansicht ist für eine der beiden folgenden Aufgaben verantwortlich: entweder einen ~django.http.HttpResponse
-Objekt zurückzugeben, das den Inhalt der angeforderten Seite enthält, oder eine Ausnahme wie ~django.http.Http404
zu werfen. Der Rest liegt an Ihnen.
Ihre Ansicht kann Datenbankaufzeichnungen lesen oder auch nicht. Sie kann ein Template-System wie das von Django verwenden - oder ein Drittanbieter-Python-Template-System - oder auch nicht. Sie kann eine PDF-Datei generieren, XML ausgeben, eine ZIP-Datei im Lauf der Zeit erstellen, alles, was Sie möchten, mit beliebigen Python-Bibliotheken, die Sie möchten.
Alles, was Django will, ist dieses ~django.http.HttpResponse
. Oder eine Ausnahme.
Damit es praktisch ist, verwenden wir die eigene Datenbank-API von Django, die wir im Tutorial 2 behandelt haben. Hier ist eine erste Version einer neuen index()
-Ansicht, die die fünf neuesten Umfragen in der System anzeigt, getrennt durch Kommas, gemäß dem Veröffentlichungsdatum:
Bearbeiten Sie die Datei polls/views.py
und ändern Sie sie so, dass sie wie folgt aussieht:
from django.http import HttpResponse
from.models import Question
def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
output = ", ".join([q.question_text for q in latest_question_list])
return HttpResponse(output)
## Lassen Sie die restlichen Ansichten (detail, results, vote) unverändert
Es gibt hier jedoch ein Problem: Die Design der Seite ist im Code der Ansicht festcodiert. Wenn Sie die Art, wie die Seite aussieht, ändern möchten, müssen Sie diesen Python-Code bearbeiten. Deshalb verwenden wir das Template-System von Django, um das Design von Python zu trennen, indem wir ein Template erstellen, das die Ansicht verwenden kann.
Erstellen Sie zunächst ein Verzeichnis namens templates
in Ihrem polls
-Verzeichnis. Django wird dort nach Templates suchen.
Die TEMPLATES
-Einstellung Ihres Projekts beschreibt, wie Django Templates laden und rendern wird. Die Standard-Einstellungsdatei konfiguriert einen DjangoTemplates
-Backend, dessen Option APP_DIRS <TEMPLATES-APP_DIRS>
auf True
gesetzt ist. Konventionell sucht DjangoTemplates
in jedem der INSTALLED_APPS
ein Unterverzeichnis namens "templates".
Innerhalb des gerade erstellten templates
-Verzeichnisses erstellen Sie ein weiteres Verzeichnis namens polls
, und innerhalb davon erstellen Sie eine Datei namens index.html
. Mit anderen Worten, Ihr Template sollte sich unter polls/templates/polls/index.html
befinden. Aufgrund der Art, wie der app_directories
-Template-Loader funktioniert, wie oben beschrieben, können Sie auf dieses Template innerhalb von Django als polls/index.html
verweisen.
Wir könnten möglicherweise damit auskommen, unsere Templates direkt in polls/templates
zu platzieren (anstatt ein weiteres polls
-Unterverzeichnis zu erstellen), aber es wäre tatsächlich ein schlechter Gedanke. Django wird das erste Template auswählen, dessen Name übereinstimmt, und wenn Sie ein Template mit demselben Namen in einer anderen Anwendung hätten, wäre Django nicht in der Lage, zwischen ihnen zu unterscheiden.
Wir müssen Django in der Lage sein, auf das richtige zu verweisen, und der beste Weg, dies sicherzustellen, ist, indem wir sie namespacing. Das heißt, indem wir diese Templates in einem anderen Verzeichnis ablegen, das nach der Anwendung selbst benannt ist.
Fügen Sie den folgenden Code in das Template ein:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Hinweis:
Um das Tutorial kürzer zu halten, verwenden alle Template-Beispiele unvollständiges HTML. In Ihren eigenen Projekten sollten Sie vollständige HTML-Dokumente verwenden.
Lassen Sie uns nun unsere index
-Ansicht in polls/views.py
aktualisieren, um das Template zu verwenden:
from django.http import HttpResponse
from django.template import loader
from.models import Question
def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
template = loader.get_template("polls/index.html")
context = {
"latest_question_list": latest_question_list,
}
return HttpResponse(template.render(context, request))
Dieser Code lädt das Template namens polls/index.html
und übergibt ihm einen Kontext. Der Kontext ist ein Dictionary, das Template-Variablennamen auf Python-Objekte abbildet.
Starten Sie den Server erneut:
python manage.py runserver 0.0.0.0:8080
Laden Sie die Seite, indem Sie Ihren Browser auf "/polls/" zeigen, und Sie sollten eine aufzählungsweise aufgelistete Liste sehen, die die Frage "What's up" aus Tutorial 2 enthält. Der Link führt zur Detailseite der Frage.
~django.shortcuts.render
Es ist eine sehr häufige Vorgehensweise, ein Template zu laden, einen Kontext zu füllen und ein ~django.http.HttpResponse
-Objekt mit dem Ergebnis des gerenderten Templates zurückzugeben. Django bietet einen Kurzschluss an. Hier ist die vollständige index()
-Ansicht, neu geschrieben:
from django.shortcuts import render
from.models import Question
def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
context = {"latest_question_list": latest_question_list}
return render(request, "polls/index.html", context)
Beachten Sie, dass wir dies in allen diesen Ansichten getan haben, brauchen wir nicht mehr ~django.template.loader
und ~django.http.HttpResponse
zu importieren (Sie sollten HttpResponse
behalten, wenn Sie immer noch die Stub-Methoden für detail
, results
und vote
haben).
Die ~django.shortcuts.render
-Funktion nimmt das Request-Objekt als erstes Argument, einen Template-Namen als zweites Argument und ein Dictionary als optionales drittes Argument entgegen. Sie gibt ein ~django.http.HttpResponse
-Objekt des angegebenen Templates zurück, das mit dem angegebenen Kontext gerendert wurde.
Nun wollen wir uns der Frage-Detail-Ansicht widmen - der Seite, die den Frage-Text für eine bestimmte Umfrage anzeigt. Hier ist die Ansicht:
from django.http import Http404
from django.shortcuts import render
from.models import Question
#...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, "polls/detail.html", {"question": question})
Das neue Konzept hier: Die Ansicht wirft die ~django.http.Http404
-Ausnahme, wenn eine Frage mit der angeforderten ID nicht existiert.
Wir werden später etwas darüber sprechen, was Sie in das polls/detail.html
-Template einfügen könnten, aber wenn Sie das obige Beispiel schnell zum Laufen bringen möchten, reicht eine Datei, die nur enthält:
{{ question }}
Das wird Ihnen für jetzt helfen.
~django.shortcuts.get_object_or_404
Es ist eine sehr häufige Vorgehensweise, ~django.db.models.query.QuerySet.get
zu verwenden und ~django.http.Http404
auszulösen, wenn das Objekt nicht existiert. Django bietet einen Kurzschluss an. Hier ist die detail()
-Ansicht, neu geschrieben:
from django.shortcuts import get_object_or_404, render
from.models import Question
#...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})
Die ~django.shortcuts.get_object_or_404
-Funktion nimmt ein Django-Modell als erstes Argument und eine beliebige Anzahl von Schlüsselwortargumenten entgegen, die sie an die ~django.db.models.query.QuerySet.get
-Funktion des Modells-Managers weitergibt. Sie wirft ~django.http.Http404
, wenn das Objekt nicht existiert.
Warum verwenden wir eine Hilfsfunktion ~django.shortcuts.get_object_or_404
anstatt automatisch die ~django.core.exceptions.ObjectDoesNotExist
-Ausnahmen auf einer höheren Ebene zu fangen oder das Model-API ~django.http.Http404
statt ~django.core.exceptions.ObjectDoesNotExist
auszulösen?
Weil das die Modellschicht mit der Ansichtsschicht verknüpfen würde. Eines der wichtigsten Designziele von Django ist die Aufrechterhaltung einer lose Kopplung. Einige kontrollierte Kopplung wird im django.shortcuts
-Modul eingeführt.
Es gibt auch eine ~django.shortcuts.get_list_or_404
-Funktion, die genauso funktioniert wie ~django.shortcuts.get_object_or_404
- nur dass sie ~django.db.models.query.QuerySet.filter
statt ~django.db.models.query.QuerySet.get
verwendet. Sie wirft ~django.http.Http404
, wenn die Liste leer ist.
Zurück zur detail()
-Ansicht unserer Umfrageanwendung. Gegeben die Kontextvariable question
, könnte das polls/detail.html
-Template so aussehen:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
Das Template-System verwendet die Punkt-Such-Syntax, um auf Variable-Attribute zuzugreifen. Im Beispiel von {{ question.question_text }}
versucht Django zunächst eine Wörterbuchsuche auf dem Objekt question
. Wenn das fehlschlägt, versucht es eine Attributsuche - was in diesem Fall funktioniert. Wenn die Attributsuche fehlgeschlagen wäre, hätte es eine Listenindexsuche versucht.
Methoden-Aufrufe erfolgen in der {% for %}<for>
-Schleife: question.choice_set.all
wird als Python-Code question.choice_set.all()
interpretiert, der ein Iterable von Choice
-Objekten zurückgibt und für die Verwendung im {% for %}<for>
-Tag geeignet ist.
Denken Sie daran, als wir den Link zu einer Frage im polls/index.html
-Template geschrieben haben, war der Link teilweise wie folgt hartcodiert:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
Das Problem mit diesem hartcodierten, eng gekoppelten Ansatz ist, dass es schwierig wird, URLs in Projekten mit vielen Templates zu ändern. Da Sie jedoch das name
-Argument in den ~django.urls.path
-Funktionen im polls.urls
-Modul definiert haben, können Sie die Abhängigkeit von bestimmten in Ihren URL-Konfigurationen definierten URL-Pfaden entfernen, indem Sie das {% url %}
-Template-Tag verwenden:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
Wie dies funktioniert, besteht darin, die in der polls.urls
-Datei definierte URL-Definition aufzurufen. Sie können genau sehen, wo der URL-Name 'detail' definiert ist, wie hier unten:
## der 'name'-Wert, wie er vom {% url %} Template-Tag aufgerufen wird
path("<int:question_id>/", views.detail, name="detail"),
Wenn Sie die URL der Umfrage-Detail-Ansicht auf etwas anderes ändern möchten, vielleicht auf etwas wie polls/specifics/12/
anstatt es im Template (oder Templates) zu tun, würden Sie es in polls/urls.py
ändern:
Sie müssen das Template überhaupt nicht ändern.
## das Wort'specifics' hinzugefügt
path("specifics/<int:question_id>/", views.detail, name="detail"),
Das Tutorial-Projekt hat nur eine App, nämlich polls
. In echten Django-Projekten könnten es fünf, zehn, zwanzig Apps oder mehr geben. Wie unterscheidet Django die URL-Namen zwischen ihnen? Beispielsweise hat die polls
-App eine detail
-Ansicht, und auch eine App auf dem gleichen Projekt, die für einen Blog ist, könnte dies tun. Wie kann man dafür sorgen, dass Django weiß, welche App-Ansicht für eine URL zu erstellen, wenn man das {% url %}
-Template-Tag verwendet?
Die Antwort ist, Namensräume zu Ihrem URLconf hinzuzufügen. Öffnen Sie die Datei polls/urls.py
und fügen Sie einen app_name
hinzu, um den Anwendungs-Namensraum festzulegen:
from django.urls import path
from. import views
app_name = "polls"
urlpatterns = [
## z.B.: /polls/
path("", views.index, name="index"),
## z.B.: /polls/5/
path("<int:question_id>/", views.detail, name="detail"),
## z.B.: /polls/5/results/
path("<int:question_id>/results/", views.results, name="results"),
## z.B.: /polls/5/vote/
path("<int:question_id>/vote/", views.vote, name="vote"),
]
Ändern Sie nun Ihr polls/index.html
-Template von:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
um auf die Namensraum-detail-Ansicht zu verweisen:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
Wenn Sie sich mit dem Schreiben von Ansichten vertraut machen, lesen Sie Form Processing and Cutting Down Our Code, um die Grundlagen der Formularverarbeitung und generischer Ansichten zu lernen.
Herzlichen Glückwunsch! Sie haben das Lab "Creating the Public Interface Views" abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.