Django Tutorial Teil 8: Benutzer-Authentifizierung und Berechtigungen
In diesem Tutorial zeigen wir Ihnen, wie Sie Benutzer in Ihre Website mit eigenen Konten einloggen lassen können und wie Sie steuern können, was sie basierend auf ihrem Berechtigungsstatus sehen und tun können. Im Rahmen dieser Demonstration erweitern wir die LocalLibrary Website, indem wir Login- und Logout-Seiten sowie benutzer- und mitarbeiterspezifische Seiten zum Anzeigen von ausgeliehenen Büchern hinzufügen.
Voraussetzungen: | Schließen Sie alle vorherigen Tutorial-Themen ab, einschließlich Django-Tutorial Teil 7: Sitzungs-Framework. |
---|---|
Ziel: | Verstehen, wie Benutzer-Authentifizierung und Berechtigungen eingerichtet und verwendet werden. |
Überblick
Django bietet ein Authentifizierungs- und Autorisierungssystem ("Berechtigungen"), das auf dem im vorherigen Tutorial behandelten Sitzungs-Framework basiert. Dieses System erlaubt es Ihnen, die Anmeldeinformationen von Benutzern zu überprüfen und festzulegen, welche Aktionen jedem Benutzer gestattet sind. Das Framework umfasst eingebaute Modelle für Users
und Groups
(eine generische Methode, um Berechtigungen mehreren Benutzern gleichzeitig zuzuweisen), Berechtigungen/Flags, die angeben, ob ein Benutzer eine Aufgabe durchführen kann, Formulare und Ansichten zum Einloggen von Benutzern und Ansichts-Tools zur Einschränkung von Inhalten.
Hinweis: Laut Django strebt das Authentifizierungssystem an, sehr generisch zu sein, und bietet daher nicht einige Funktionen anderer Webauthentifizierungssysteme. Lösungen für einige häufige Probleme sind als Drittanbieterpakete verfügbar. Beispielsweise das Drosseln von Login-Versuchen und die Authentifizierung gegen Dritte (z. B. OAuth).
In diesem Tutorial zeigen wir Ihnen, wie Sie die Benutzer-Authentifizierung auf der LocalLibrary Website aktivieren, Ihre eigenen Login- und Logout-Seiten erstellen, Berechtigungen zu Ihren Modellen hinzufügen und den Zugriff auf Seiten steuern. Wir verwenden die Authentifizierung/Berechtigungen, um Listen ausgeliehener Bücher sowohl für Benutzer als auch für Bibliothekare anzuzeigen.
Das Authentifizierungssystem ist sehr flexibel, und Sie können Ihre URLs, Formulare, Ansichten und Vorlagen von Grund auf neu erstellen und dabei nur die bereitgestellte API verwenden, um den Benutzer einzuloggen. In diesem Artikel werden wir jedoch die "Stock"-Authentifizierungsansichten und -formulare von Django für unsere Login- und Logout-Seiten verwenden. Wir müssen zwar einige Vorlagen erstellen, aber das ist ziemlich einfach.
Wir zeigen Ihnen auch, wie Sie Berechtigungen erstellen und den Anmeldestatus und die Berechtigungen sowohl in Ansichten als auch in Vorlagen überprüfen können.
Authentifizierung aktivieren
Die Authentifizierung wurde automatisch aktiviert, als wir die Skeleton-Website erstellt haben (im Tutorial 2), sodass Sie an dieser Stelle nichts weiter tun müssen.
Hinweis:
Die notwendige Konfiguration wurde bereits für uns vorgenommen, als wir die App mit dem Befehl django-admin startproject
erstellt haben. Die Datenbanktabellen für Benutzer- und Modellberechtigungen wurden erstellt, als wir zum ersten Mal python manage.py migrate
aufgerufen haben.
Die Konfiguration ist in den Sektionen INSTALLED_APPS
und MIDDLEWARE
der Projektdatei (django-locallibrary-tutorial/locallibrary/settings.py) eingerichtet, wie unten gezeigt:
INSTALLED_APPS = [
# …
'django.contrib.auth', # Core authentication framework and its default models.
'django.contrib.contenttypes', # Django content type system (allows permissions to be associated with models).
# …
MIDDLEWARE = [
# …
'django.contrib.sessions.middleware.SessionMiddleware', # Manages sessions across requests
# …
'django.contrib.auth.middleware.AuthenticationMiddleware', # Associates users with requests using sessions.
# …
Benutzer und Gruppen erstellen
Sie haben Ihren ersten Benutzer bereits erstellt, als wir uns das Django-Admin-Interface im Tutorial 4 angesehen haben (dies war ein Superuser, erstellt mit dem Befehl python manage.py createsuperuser
). Unser Superuser ist bereits authentifiziert und hat alle Berechtigungen, daher müssen wir einen Testbenutzer erstellen, der einen normalen Website-Benutzer repräsentiert. Wir werden das Admin-Interface verwenden, um unsere locallibrary-Gruppen und Website-Logins zu erstellen, da dies eine der schnellsten Möglichkeiten ist.
Hinweis: Sie können Benutzer auch programmatisch wie unten gezeigt erstellen. Sie müssen dies beispielsweise tun, wenn Sie eine Schnittstelle entwickeln, um "normalen" Benutzern das Erstellen ihrer eigenen Logins zu ermöglichen (Sie sollten den meisten Benutzern keinen Zugriff auf das Admin-Interface geben).
from django.contrib.auth.models import User
# Benutzer erstellen und in der Datenbank speichern
user = User.objects.create_user('meinbenutzername', '[email protected]', 'meinpasswort')
# Felder aktualisieren und erneut speichern
user.first_name = 'Tyrone'
user.last_name = 'Citizen'
user.save()
Beachten Sie jedoch, dass es dringend empfohlen wird, ein benutzerdefiniertes Benutzermodell beim Starten eines Projekts einzurichten, da Sie es zukünftig bei Bedarf leicht anpassen können. Bei Verwendung eines benutzerdefinierten Benutzermodells würde der Code zum Erstellen desselben Benutzers wie folgt aussehen:
# Aktuelles Benutzermodell aus den Einstellungen abrufen
from django.contrib.auth import get_user_model
User = get_user_model()
# Benutzer aus Modell erstellen und in der Datenbank speichern
user = User.objects.create_user('meinbenutzername', '[email protected]', 'meinpasswort')
# Felder aktualisieren und erneut speichern
user.first_name = 'Tyrone'
user.last_name = 'Citizen'
user.save()
Weitere Informationen finden Sie unter Ein benutzerdefiniertes Benutzermodell beim Start eines Projekts verwenden (Django-Dokumentation).
Im Folgenden werden wir zuerst eine Gruppe und dann einen Benutzer erstellen. Auch wenn wir derzeit noch keine Berechtigungen für unsere Bibliotheksmitglieder hinzufügen müssen, wird es später viel einfacher sein, diese einmal für die Gruppe statt einzeln für jedes Mitglied hinzuzufügen.
Starten Sie den Entwicklungsserver und navigieren Sie in Ihrem lokalen Webbrowser zum Admin-Interface (http://127.0.0.1:8000/admin/
). Melden Sie sich mit den Anmeldedaten Ihres Superuser-Kontos an der Seite an. Die oberste Ebene der Admin-Site zeigt alle Ihre Modelle, sortiert nach "Django-Anwendung". Im Authentifizierungs- und Autorisierungs-Abschnitt können Sie auf die Links Benutzer oder Gruppen klicken, um deren bestehende Datensätze anzuzeigen.
Lassen Sie uns zuerst eine neue Gruppe für unsere Bibliotheksmitglieder erstellen.
- Klicken Sie auf die Schaltfläche Hinzufügen (neben Gruppe), um eine neue Gruppe zu erstellen; geben Sie den Namen "Library Members" für die Gruppe ein.
- Wir benötigen keine Berechtigungen für die Gruppe, also drücken Sie einfach SPEICHERN (Sie werden zu einer Liste von Gruppen weitergeleitet).
Nun erstellen wir einen Benutzer:
-
Navigieren Sie zurück zur Startseite der Admin-Site
-
Klicken Sie auf die Schaltfläche Hinzufügen neben Benutzer, um das Dialogfeld Benutzer hinzufügen zu öffnen.
-
Geben Sie einen geeigneten Benutzernamen sowie Passwort/Passwortbestätigung für Ihren Testbenutzer ein
-
Drücken Sie SPEICHERN, um den Benutzer zu erstellen.
Die Admin-Site erstellt den neuen Benutzer und leitet Sie sofort zu einem Benutzer ändern-Bildschirm weiter, in dem Sie Ihren Benutzernamen ändern und Informationen zu den optionalen Feldern des Benutzermodells hinzufügen können. Diese Felder umfassen den Vornamen, Nachnamen, die E-Mail-Adresse und den Status und die Berechtigungen des Benutzers (nur das Aktiv-Flag sollte gesetzt werden). Weiter unten können Sie die Gruppen und Berechtigungen des Benutzers angeben und wichtige Daten im Zusammenhang mit dem Benutzer einsehen (z. B. sein Beitrittsdatum und sein letztes Anmeldedatum).
-
Im Abschnitt Gruppen wählen Sie die Gruppe Library Member aus der Liste der Verfügbaren Gruppen aus und drücken dann auf den nach rechts zeigenden Pfeil zwischen den Boxen, um sie in die Box Ausgewählte Gruppen zu verschieben.
-
Wir müssen hier nichts weiter tun, also wählen Sie einfach noch einmal SPEICHERN, um zur Liste der Benutzer zu wechseln.
Das war's! Jetzt haben Sie ein "normales Bibliotheksmitglied"-Konto, das Sie für Tests verwenden können (sobald wir die Seiten implementiert haben, die es ihnen ermöglichen, sich einzuloggen).
Hinweis: Sie sollten versuchen, einen weiteren Bibliotheksbenutzer zu erstellen. Erstellen Sie auch eine Gruppe für Bibliothekare und fügen Sie dieser ebenfalls einen Benutzer hinzu!
Einrichtung Ihrer Authentifizierungsansichten
Django stellt fast alles zur Verfügung, was Sie benötigen, um Authentifizierungsseiten zu erstellen, die sich um das Einloggen, Ausloggen und das Passwort-Management kümmern. Dies beinhaltet einen URL-Mapper, Ansichten und Formulare, aber keine Vorlagen — diese müssen wir selbst erstellen!
In diesem Abschnitt zeigen wir, wie das Standardsystem in die LocalLibrary Website integriert und die Vorlagen erstellt werden. Wir platzieren diese im Hauptprojekt-URLs.
Hinweis: Sie müssen keinen dieser Codes verwenden, aber es ist wahrscheinlich, dass Sie das möchten, weil es die Dinge wesentlich erleichtert. Sie werden fast sicher den Formularverarbeitungscode ändern müssen, wenn Sie Ihr Benutzermodell ändern. Dennoch können Sie die Standard-Ansichtsfunktionen verwenden.
Hinweis: In diesem Fall könnten wir die Authentifizierungsseiten, einschließlich der URLs und Vorlagen, vernünftigerweise in unserer Kataloganwendung unterbringen. Wenn wir jedoch mehrere Anwendungen hätten, wäre es besser, dieses gemeinsame Login-Verhalten zu trennen und für die gesamte Site verfügbar zu machen, was wir hier gezeigt haben!
Projekt-URLs
Fügen Sie Folgendes am Ende der Projektdatei urls.py (django-locallibrary-tutorial/locallibrary/urls.py) hinzu:
# Add Django site authentication urls (for login, logout, password management)
urlpatterns += [
path('accounts/', include('django.contrib.auth.urls')),
]
Navigieren Sie zur URL http://127.0.0.1:8000/accounts/
(beachten Sie den abschließenden Schrägstrich!).
Django zeigt einen Fehler an, dass es keine Zuordnung für diese URL finden konnte, und listet alle URLs auf, die es versucht hat.
Daraus können Sie die URLs sehen, die funktionieren werden, sobald wir Vorlagen erstellt haben.
Hinweis:
Durch das Hinzufügen des accounts/
Pfads, wie oben gezeigt, werden die folgenden URLs hinzugefügt, zusammen mit Namen (in eckigen Klammern angegeben), die verwendet werden können, um die URL-Zuordnungen umzukehren. Sie müssen nichts weiter implementieren — die obige URL-Zuordnung ordnet automatisch die unten genannten URLs zu.
accounts/ login/ [name='login']
accounts/ logout/ [name='logout']
accounts/ password_change/ [name='password_change']
accounts/ password_change/done/ [name='password_change_done']
accounts/ password_reset/ [name='password_reset']
accounts/ password_reset/done/ [name='password_reset_done']
accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/ reset/done/ [name='password_reset_complete']
Versuchen Sie nun, zur Login-URL (http://127.0.0.1:8000/accounts/login/
) zu navigieren. Dies wird erneut fehlschlagen, diesmal jedoch mit einem Fehler, der Ihnen mitteilt, dass wir die erforderliche Vorlage (registration/login.html) im Vorlagesuchpfad vermissen.
Sie werden die folgenden Zeilen im gelben Bereich oben sehen:
Exception Type: TemplateDoesNotExist
Exception Value: registration/login.html
Der nächste Schritt besteht darin, ein Verzeichnis für die Vorlagen namens "registration" zu erstellen und dann die login.html Datei hinzuzufügen.
Vorlagenverzeichnis
Die URLs (und implizit, Ansichten), die wir gerade hinzugefügt haben, erwarten, dass ihre zugeordneten Vorlagen in einem Verzeichnis /registration/ irgendwo im Vorlagesuchpfad zu finden sind.
Für diese Website platzieren wir unsere HTML-Seiten im Verzeichnis templates/registration/. Dieses Verzeichnis sollte sich im Root-Verzeichnis Ihres Projekts befinden, das heißt im selben Verzeichnis wie die catalog und locallibrary Ordner. Bitte erstellen Sie diese Ordner jetzt.
Hinweis: Ihre Ordnerstruktur sollte jetzt wie unten gezeigt aussehen:
django-locallibrary-tutorial/ # Django oberster Projektordner catalog/ locallibrary/ templates/ registration/
Um das templates Verzeichnis für den Vorlagenladeprogramm sichtbar zu machen, müssen wir es im Vorlagesuchpfad hinzufügen. Öffnen Sie die Projekteinstellungen (/django-locallibrary-tutorial/locallibrary/settings.py).
Importieren Sie dann das os
Modul (fügen Sie folgende Zeile nahe der Spitze der Datei hinzu, falls sie noch nicht vorhanden ist).
import os # needed by code below
Aktualisieren Sie die TEMPLATES
Sektion der 'DIRS'
Zeile wie gezeigt:
# …
TEMPLATES = [
{
# …
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
# …
Login-Vorlage
Warnung: Die in diesem Artikel bereitgestellten Authentifizierungsvorlagen sind eine sehr einfache/wenig modifizierte Version der Demonstrations-Login-Vorlagen von Django. Möglicherweise müssen Sie sie für Ihre eigene Verwendung anpassen!
Erstellen Sie eine neue HTML-Datei unter /django-locallibrary-tutorial/templates/registration/login.html und geben Sie ihr folgenden Inhalt:
{% extends "base_generic.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>
{# Assumes you set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
{% endblock %}
Diese Vorlage weist einige Ähnlichkeiten mit denen auf, die wir zuvor gesehen haben — sie erweitert unsere Basismaske und überschreibt den content
Block. Der Rest des Codes ist ein ziemlich standardmäßiger Formularverarbeitungscode, den wir in einem späteren Tutorial besprechen werden. Alles, was Sie für den Moment wissen müssen, ist, dass dies ein Formular anzeigen wird, in dem Sie Ihren Benutzernamen und Ihr Passwort eingeben können, und dass, wenn Sie ungültige Werte eingeben, Sie aufgefordert werden, korrekte Werte einzugeben, wenn die Seite aktualisiert wird.
Navigieren Sie zurück zur Login-Seite (http://127.0.0.1:8000/accounts/login/
), nachdem Sie Ihre Vorlage gespeichert haben, und Sie sollten etwas Ähnliches wie dies sehen:
Wenn Sie sich mit gültigen Anmeldedaten einloggen, werden Sie auf eine andere Seite umgeleitet (standardmäßig wird dies http://127.0.0.1:8000/accounts/profile/
sein). Das Problem ist, dass Django standardmäßig erwartet, dass Sie nach dem Einloggen zu einer Profilseite weitergeleitet werden möchten, was möglicherweise nicht der Fall ist. Da Sie diese Seite noch nicht definiert haben, erhalten Sie einen weiteren Fehler!
Öffnen Sie die Projekteinstellungen (/django-locallibrary-tutorial/locallibrary/settings.py) und fügen Sie den unten stehenden Text hinzu. Jetzt sollten Sie standardmäßig auf die Startseite der Seite weitergeleitet werden, wenn Sie sich einloggen.
# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
Logout-Vorlage
Wenn Sie zur Logout-URL (http://127.0.0.1:8000/accounts/logout/
) navigieren, erhalten Sie einen Fehler, weil Django 5 das Ausloggen nur mit POST
, nicht mit GET
zulässt.
Wir werden in Kürze ein Formular hinzufügen, das Sie zum Abmelden verwenden können, aber zuerst erstellen wir die Seite, zu der Benutzer nach dem Ausloggen geleitet werden.
Erstellen und öffnen /django-locallibrary-tutorial/templates/registration/logged_out.html. Kopieren Sie den untenstehenden Text:
{% extends "base_generic.html" %}
{% block content %}
<p>Logged out!</p>
<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}
Diese Vorlage ist sehr einfach. Sie zeigt lediglich eine Nachricht an, die Ihnen mitteilt, dass Sie abgemeldet wurden, und bietet einen Link, den Sie drücken können, um zurück zur Anmeldeseite zu gehen. Der Bildschirm wird so dargestellt (nach dem Ausloggen):
Passwort-Reset-Vorlagen
Das Standardpasswort-Reset-System verwendet E-Mail, um dem Benutzer einen Reset-Link zu senden. Sie müssen Formulare erstellen, um die E-Mail-Adresse des Benutzers zu erhalten, die E-Mail zu senden, ihnen zu erlauben, ein neues Passwort einzugeben und zu vermerken, wenn der gesamte Prozess abgeschlossen ist.
Die folgenden Vorlagen können als Basis verwendet werden.
Passwort-Reset-Formular
Dies ist das Formular, das zur Eingabe der E-Mail-Adresse des Benutzers verwendet wird (um die Passwort-Reset-E-Mail zu senden). Erstellen Sie /django-locallibrary-tutorial/templates/registration/password_reset_form.html und geben Sie ihm folgenden Inhalt:
{% extends "base_generic.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{% if form.email.errors %}
{{ form.email.errors }}
{% endif %}
<p>{{ form.email }}</p>
<input type="submit" class="btn btn-default btn-lg" value="Reset password">
</form>
{% endblock %}
Passwort-Reset durchgeführt
Dieses Formular wird angezeigt, nachdem Ihre E-Mail-Adresse erfasst wurde. Erstellen Sie /django-locallibrary-tutorial/templates/registration/password_reset_done.html und geben Sie ihm folgenden Inhalt:
{% extends "base_generic.html" %}
{% block content %}
<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
{% endblock %}
Passwort-Reset E-Mail
Diese Vorlage liefert den Text der HTML-E-Mail, die wir an Benutzer senden werden, um den Reset-Link zu senden. Erstellen Sie /django-locallibrary-tutorial/templates/registration/password_reset_email.html und geben Sie ihm folgenden Inhalt:
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
Passwort-Reset bestätigen
Diese Seite ist der Ort, an dem Sie Ihr neues Passwort eingeben, nachdem Sie auf den Link in der Passwort-Reset-E-Mail geklickt haben. Erstellen Sie /django-locallibrary-tutorial/templates/registration/password_reset_confirm.html und geben Sie ihm folgenden Inhalt:
{% extends "base_generic.html" %}
{% block content %}
{% if validlink %}
<p>Please enter (and confirm) your new password.</p>
<form action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>{{ form.new_password1.errors }}
<label for="id_new_password1">New password:</label></td>
<td>{{ form.new_password1 }}</td>
</tr>
<tr>
<td>{{ form.new_password2.errors }}
<label for="id_new_password2">Confirm password:</label></td>
<td>{{ form.new_password2 }}</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Change my password"></td>
</tr>
</table>
</form>
{% else %}
<h1>Password reset failed</h1>
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}
Passwort-Reset abgeschlossen
Dies ist die letzte Passwort-Reset-Vorlage, die angezeigt wird, um Sie darauf hinzuweisen, dass der Passwort-Reset erfolgreich war. Erstellen Sie /django-locallibrary-tutorial/templates/registration/password_reset_complete.html und geben Sie ihm folgenden Inhalt:
{% extends "base_generic.html" %}
{% block content %}
<h1>The password has been changed!</h1>
<p><a href="{% url 'login' %}">log in again?</a></p>
{% endblock %}
Testen der neuen Authentifizierungsseiten
Nachdem Sie die URL-Konfiguration hinzugefügt und all diese Vorlagen erstellt haben, sollten die Authentifizierungsseiten (außer Logout) nun einfach funktionieren!
Sie können die neuen Authentifizierungsseiten testen, indem Sie zuerst versuchen, sich mit Ihrem Superuser-Konto über die URL http://127.0.0.1:8000/accounts/login/
einzuloggen.
Sie können die Passwort-Reset-Funktionalität über den Link auf der Login-Seite testen. Beachten Sie, dass Django nur Passwortrücksetzungen an bereits in seiner Datenbank gespeicherte Adressen (Benutzer) senden wird!
Bitte beachten Sie, dass Sie das Konto-Logout noch nicht testen können, da Abmeldeanforderungen als POST
und nicht als GET
gesendet werden müssen.
Hinweis: Das Passwort-Reset-System erfordert, dass Ihre Website E-Mail unterstützt, was über den Umfang dieses Artikels hinausgeht, sodass dieser Teil noch nicht funktioniert. Fügen Sie zum Testen die folgende Zeile am Ende Ihrer settings.py Datei hinzu. Dadurch werden alle gesendeten E-Mails in die Konsole geloggt (damit Sie den Passwort-Reset-Link aus der Konsole kopieren können).
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Weitere Informationen finden Sie unter E-Mail senden (Django-Dokumentation).
Testen gegenüber authentifizierten Benutzern
Dieser Abschnitt behandelt, was wir tun können, um selektiv steuern zu können, welchen Inhalt der Benutzer basierend auf seinem Anmeldestatus sieht.
Testen in Vorlagen
Sie können in Vorlagen Informationen über den aktuell eingelog
gten Benutzer mit der {{ user }}
Template-Variable erhalten (diese wird standardmäßig bei der Einrichtung des Projekts dem Vorlagenkontext hinzugefügt).
Typischerweise testen Sie zuerst die {{ user.is_authenticated }}
Template-Variable, um festzustellen, ob der Benutzer zum Sehen bestimmter Inhalte berechtigt ist. Um dies zu demonstrieren, aktualisieren wir als nächstes unsere Seitenleiste, um einen "Login"-Link anzuzeigen, wenn der Benutzer ausgeloggt ist, und einen "Logout"-Link, wenn er eingeloggt ist.
Öffnen Sie die Basismaske (/django-locallibrary-tutorial/catalog/templates/base_generic.html) und kopieren Sie den folgenden Text in den sidebar
Block, unmittelbar vor dem endblock
Template-Tag.
<ul class="sidebar-nav">
…
{% if user.is_authenticated %}
<li>User: {{ user.get_username }}</li>
<li>
<form id="logout-form" method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit" class="btn btn-link">Logout</button>
</form>
</li>
{% else %}
<li><a href="{% url 'login' %}?next={{ request.path }}">Login</a></li>
{% endif %}
…
</ul>
Wie Sie sehen, verwenden wir if
/ else
/ endif
Template-Tags, um Text bedingt anzuzeigen, basierend darauf, ob {{ user.is_authenticated }}
wahr ist. Wenn der Benutzer authentifiziert ist, wissen wir, dass wir einen gültigen Benutzer haben, und rufen {{ user.get_username }}
auf, um seinen Namen anzuzeigen.
Wir erstellen die URL des Login-Links mit dem url
Template-Tag und dem Namen der login
URL-Konfiguration. Beachten Sie auch, wie wir ?next={{ request.path }}
am Ende der URL hinzugefügt haben. Dies fügt der verlinkten URL einen URL-Parameter next
hinzu, der die Adresse (URL) der aktuellen Seite enthält. Nachdem sich der Benutzer erfolgreich eingeloggt hat, verwendet die Ansicht diesen next
Wert, um den Benutzer zurück auf die Seite umzuleiten, auf der er ursprünglich auf den Login-Link geklickt hat.
Der Logout-Vorlagencode unterscheidet sich, da seit Django 5 zum Ausloggen mit POST
zur admin:logout
URL gesendet werden muss, mit einem Formular mit einer Schaltfläche.
Standardmäßig würde dies als Schaltfläche dargestellt, Sie können jedoch die Schaltfläche so gestalten, dass sie als Link angezeigt wird.
Für dieses Beispiel verwenden wir Bootstrap, sodass wir die Schaltfläche wie einen Link aussehen lassen, indem wir class="btn btn-link"
anwenden.
Sie müssen dieser Datei auch die folgenden Stile hinzufügen /django-locallibrary-tutorial/catalog/static/css/styles.css, um den Logout-Link neben allen anderen Seitenleisten-Links korrekt zu positionieren:
#logout-form {
display: inline;
}
#logout-form button {
padding: 0;
margin: 0;
}
Probieren Sie es aus, indem Sie die Login/Logout-Links in der Seitenleiste anklicken. Sie sollten zu den oben im Vorlagenverzeichnis definierten Logout/Login-Seiten gelangen.
Testen in Ansichten
Wenn Sie funktionbasierte Ansichten verwenden, können Sie den Zugriff auf Ihre Funktionen am einfachsten einschränken, indem Sie den login_required
Dekorator auf Ihre Ansichts-Funktion anwenden, wie unten gezeigt. Wenn der Benutzer eingeloggt ist, wird Ihr Ansichts-Code normal ausgeführt. Wenn der Benutzer nicht eingeloggt ist, wird er zur im Projekt definierten Login-URL (settings.LOGIN_URL
) umgeleitet und der aktuelle absolute Pfad als next
URL-Parameter übergeben. Wenn es dem Benutzer gelingt, sich einzuloggen, wird er auf diese Seite zurückgeleitet, diesmal jedoch authentifiziert.
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
# …
Hinweis:
Sie können dasselbe auch manuell tun, indem Sie auf request.user.is_authenticated
testen, aber der Dekorator ist viel praktischer!
Ebenso besteht die einfachste Möglichkeit, den Zugriff auf eingeloggte Benutzer in Ihren klassenbasierten Ansichten einzuschränken, darin, von LoginRequiredMixin
abzuleiten. Sie müssen diesen Mixin zuerst in der Superklasse-Liste angeben, bevor die Hauptansichtsklasse angegeben wird.
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
# …
Dies hat genau dasselbe Umleitungsverhalten wie der login_required
Dekorator. Sie können auch eine alternative Adresse angeben, zu der der Benutzer weitergeleitet wird, wenn er nicht authentifiziert ist (login_url
), und einen URL-Parameternamen anstelle von next
, um den aktuellen absoluten Pfad zu verwenden (redirect_field_name
).
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
Für weitere Details lesen Sie in der Django-Dokumentation hier nach.
Beispiel — Liste der Bücher des aktuellen Benutzers
Jetzt, da wir wissen, wie man eine Seite auf einen bestimmten Benutzer beschränkt, lassen Sie uns eine Ansicht von Büchern erstellen, die der aktuelle Benutzer ausgeliehen hat.
Leider haben wir noch keine Möglichkeit, Benutzern Bücher auszuleihen! Bevor wir also die Buchliste erstellen können, erweitern wir zunächst das BookInstance
Modell, um das Konzept des Ausleihens zu unterstützen, und verwenden die Django Admin Anwendung, um eine Anzahl von Büchern an unseren Testbenutzer zu verleihen.
Modelle
Zuerst müssen wir es möglich machen, dass Benutzer eine BookInstance
ausleihen können (wir haben bereits einen status
und ein due_back
Datum, aber wir haben noch keine Verbindung zwischen diesem Modell und einem bestimmten Benutzer. Wir erstellen eine mit einem ForeignKey
(eins-zu-viele) Feld. Wir benötigen auch einen einfachen Mechanismus, um zu testen, ob ein ausgeliehenes Buch überfällig ist.
Öffnen Sie catalog/models.py und importieren Sie die settings
von django.conf
(fügen Sie dies direkt unter der vorherigen Importzeile am Anfang der Datei hinzu, damit die Einstellungen im nachfolgenden Code verwendet werden können):
from django.conf import settings
Fügen Sie als nächstes das borrower
Feld zum BookInstance
Modell hinzu und setzen Sie das Benutzermodell für den Schlüssel als Wert der Einstellung AUTH_USER_MODEL
.
Da wir die Einstellung mit einem benutzerdefinierten Benutzermodell nicht überschrieben haben, wird auf das Standard User
Modell von django.contrib.auth.models
abgebildet.
borrower = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
Hinweis:
Auf diese Weise lassen sich die Modelle importieren, reduziert sich der Arbeitsaufwand, wenn Sie später feststellen, dass Sie ein benutzerdefiniertes Benutzermodell benötigen.
Dieses Tutorial verwendet das Standardmodell, sodass Sie stattdessen das User
Modell direkt mit den folgenden Zeilen importieren könnten:
from django.contrib.auth.models import User
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
Während wir hier sind, fügen wir eine Eigenschaft hinzu, die wir aus unseren Vorlagen aufrufen können, um festzustellen, ob ein bestimmtes Buch ein überfälliges Exemplar ist. Während wir dies im Template selbst berechnen könnten, wäre es viel effizienter, eine Eigenschaft wie unten gezeigt zu verwenden.
Fügen Sie dies irgendwo in der Nähe des Anfangs der Datei hinzu:
from datetime import date
Fügen Sie dann die folgende Eigenschaftsdefinition zur BookInstance
Klasse hinzu:
Hinweis:
Der folgende Code verwendet die bool()
Funktion von Python, die ein Objekt oder das Ergebnis eines Ausdrucks auswertet und True
zurückgibt, es sei denn, das Ergebnis ist "falsy", in diesem Fall wird False
zurückgegeben.
In Python ist ein Objekt falsy (wertet sich als False
), wenn es: leer ist (wie []
, ()
, {}
), 0
, None
oder wenn es False
ist.
@property
def is_overdue(self):
"""Determines if the book is overdue based on due date and current date."""
return bool(self.due_back and date.today() > self.due_back)
Hinweis:
Wir überprüfen zuerst, ob due_back
leer ist, bevor wir einen Vergleich anstellen. Ein leeres due_back
Feld würde Django einen Fehler verursachen, anstatt die Seite anzuzeigen: leere Werte sind nicht vergleichbar. Das ist nicht etwas, das wir den Benutzern zumuten wollen!
Da wir unsere Modelle aktualisiert haben, müssen wir neue Migrationen auf dem Projekt durchführen und diese Migrationen anwenden:
python3 manage.py makemigrations
python3 manage.py migrate
Admin
Öffnen Sie nun catalog/admin.py, und fügen Sie das borrower
Feld zur BookInstanceAdmin
Klasse sowohl in list_display
als auch in fieldsets
wie unten gezeigt hinzu.
Dies wird das Feld im Admin Bereich sichtbar machen und es uns ermöglichen, einem BookInstance
bei Bedarf einen User
zuzuweisen.
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
list_display = ('book', 'status', 'borrower', 'due_back', 'id')
list_filter = ('status', 'due_back')
fieldsets = (
(None, {
'fields': ('book', 'imprint', 'id')
}),
('Availability', {
'fields': ('status', 'due_back', 'borrower')
}),
)
Leihen Sie ein paar Bücher aus
Da es nun möglich ist, Bücher an einen bestimmten Benutzer zu verleihen, leihen Sie eine Anzahl von BookInstance
Datensätzen aus. Setzen Sie ihr borrowed
Feld auf Ihren Testbenutzer, stellen Sie den status
auf "Ausgeliehen" und setzen Sie Fälligkeitsdaten sowohl in die Zukunft als auch in die Vergangenheit.
Hinweis: Wir werden den Prozess nicht ausbuchstabieren, da Sie bereits wissen, wie Sie das Admin-Interface verwenden!
Ansicht der ausgeliehenen Bücher
Jetzt fügen wir eine Ansicht hinzu, um die Liste aller Bücher zu erhalten, die dem aktuellen Benutzer ausgeliehen wurden. Wir verwenden dieselbe generische listenbasierte Klassenansicht, mit der wir vertraut sind, importieren und leiten jedoch auch von LoginRequiredMixin
ab, sodass nur ein angemeldeter Benutzer diese Ansicht aufrufen kann. Wir werden auch einen template_name
angeben, anstatt den Standard zu verwenden, weil wir möglicherweise mehrere Listen von BookInstance-Datensätzen mit unterschiedlichen Ansichten und Vorlagen haben.
Fügen Sie Folgendes zu catalog/views.py hinzu:
from django.contrib.auth.mixins import LoginRequiredMixin
class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
"""Generic class-based view listing books on loan to current user."""
model = BookInstance
template_name = 'catalog/bookinstance_list_borrowed_user.html'
paginate_by = 10
def get_queryset(self):
return (
BookInstance.objects.filter(borrower=self.request.user)
.filter(status__exact='o')
.order_by('due_back')
)
Um unsere Abfrage nur auf die BookInstance
Objekte für den aktuellen Benutzer zu beschränken, implementieren wir get_queryset()
wie oben gezeigt. Beachten Sie, dass "o" der gespeicherte Code für "ausgeliehen" ist und wir nach dem due_back
Datum ordnen, damit die ältesten Gegenstände zuerst angezeigt werden.
URL-Konfiguration für ausgeliehene Bücher
Öffnen Sie nun /catalog/urls.py und fügen Sie ein path()
hinzu, das auf die obige Ansicht verweist (Sie können den untenstehenden Text einfach am Ende der Datei kopieren).
urlpatterns += [
path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
]
Vorlage für ausgeliehene Bücher
Jetzt müssen wir nur noch eine Vorlage für diese Seite hinzufügen. Erstellen Sie zuerst die Vorlagendatei /catalog/templates/catalog/bookinstance_list_borrowed_user.html und geben Sie ihr folgenden Inhalt:
{% extends "base_generic.html" %}
{% block content %}
<h1>Borrowed books</h1>
{% if bookinstance_list %}
<ul>
{% for bookinst in bookinstance_list %}
<li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
<a href="{% url 'book-detail' bookinst.book.pk %}">{{ bookinst.book.title }}</a> ({{ bookinst.due_back }})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books borrowed.</p>
{% endif %}
{% endblock %}
Diese Vorlage ist sehr ähnlich zu denen, die wir zuvor für die Book
und Author
Objekte erstellt haben.
Das einzige "Neue" hier ist, dass wir die Methode verwenden, die wir im Modell hinzugefügt haben (bookinst.is_overdue
) und sie verwenden, um die Farbe von überfälligen Gegenständen zu ändern.
Wenn der Entwicklungsserver läuft, sollten Sie die Liste jetzt für einen angemeldeten Benutzer in Ihrem Browser unter http://127.0.0.1:8000/catalog/mybooks/
ansehen können. Probieren Sie dies mit Ihrem Benutzer ein- und ausgeloggt aus (im zweiten Fall sollten Sie zur Login-Seite weitergeleitet werden).
Fügen Sie die Liste zur Seitenleiste hinzu
Der allerletzte Schritt ist, einen Link zu dieser neuen Seite in die Seitenleiste einzufügen. Wir platzieren dies im selben Abschnitt, in dem wir andere Informationen für den angemeldeten Benutzer anzeigen.
Öffnen Sie die Basismaske (/django-locallibrary-tutorial/catalog/templates/base_generic.html) und fügen Sie die Zeile "Meine ausgeborgten Bücher" zur Seitenleiste in der unten gezeigten Position hinzu.
<ul class="sidebar-nav">
{% if user.is_authenticated %}
<li>User: {{ user.get_username }}</li>
<li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
<li>
<form id="logout-form" method="post" action="{% url 'admin:logout' %}">
{% csrf_token %}
<button type="submit" class="btn btn-link">Logout</button>
</form>
</li>
{% else %}
<li><a href="{% url 'login' %}?next={{ request.path }}">Login</a></li>
{% endif %}
</ul>
Wie sieht es aus?
Wenn ein Benutzer eingeloggt ist, sieht er den Meine ausgeborgten Bücher Link in der Seitenleiste und die Liste der Bücher wird wie unten gezeigt angezeigt (das erste Buch hat kein Fälligkeitsdatum, was ein Fehler ist, den wir in einem späteren Tutorial beheben hoffen!).
Berechtigungen
Berechtigungen sind mit Modellen verknüpft und definieren die Operationen, die auf eine Modellinstanz durch einen Benutzer mit Berechtigung durchgeführt werden können. Standardmäßig gibt Django add
, change
und delete
Berechtigungen für alle Modelle, die es Benutzern mit den Berechtigungen ermöglichen, die zugehörigen Aktionen über das Admin-Interface durchzuführen. Sie können Ihre eigenen Berechtigungen für Modelle definieren und sie spezifischen Benutzern zuweisen. Sie können auch die Berechtigungen ändern, die mit verschiedenen Instanzen desselben Modells verknüpft sind.
Das Testen auf Berechtigungen in Ansichten und Vorlagen ähnelt dann sehr dem Testen auf den Authentifizierungsstatus (und tatsächlich testet das Testen auf Berechtigungen auch auf Authentifizierung).
Modelle
Das Definieren von Berechtigungen erfolgt im class Meta
Abschnitt des Modells, mit dem permissions
Feld.
Sie können so viele Berechtigungen angeben, wie Sie benötigen, in einem Tupel, wobei jede Berechtigung selbst in einem verschachtelten Tupel enthalten ist, das den Berechtigungsnamen und -anzeigewert enthält.
Zum Beispiel könnten wir eine Berechtigung definieren, um einem Benutzer zu erlauben, zu markieren, dass ein Buch zurückgebracht wurde, wie gezeigt:
class BookInstance(models.Model):
# …
class Meta:
# …
permissions = (("can_mark_returned", "Set book as returned"),)
Dann könnten wir die Berechtigung im Admin-Interface einer "Bibliothekar"-Gruppe zuweisen.
Öffnen Sie catalog/models.py und fügen Sie die Berechtigung wie oben gezeigt hinzu. Sie müssen Ihre Migrationen erneut durchlaufen (rufen Sie python3 manage.py makemigrations
und python3 manage.py migrate
auf), um die Datenbank entsprechend zu aktualisieren.
Vorlagen
Die Berechtigungen des aktuellen Benutzers werden in einer Templatevariablen namens {{ perms }}
gespeichert. Sie können prüfen, ob der aktuelle Benutzer eine bestimmte Berechtigung hat, indem Sie den spezifischen Variablennamen innerhalb der zugehörigen Django "App" verwenden — z. B., {{ perms.catalog.can_mark_returned }}
wird True
sein, wenn der Benutzer diese Berechtigung hat, und False
andernfalls. Wir testen die Berechtigung in der Regel mit dem {% if %}
Tag der Vorlage, wie gezeigt:
{% if perms.catalog.can_mark_returned %}
<!-- We can mark a BookInstance as returned. -->
<!-- Perhaps add code to link to a "book return" view here. -->
{% endif %}
Ansichten
Berechtigungen können in funktionbasierten Ansichten mithilfe des permission_required
Dekorators oder in einer klassenbasierten Ansicht mithilfe des PermissionRequiredMixin
getestet werden. Das Muster ist dasselbe wie bei der Login-Authentifizierung, obwohl Sie natürlich möglicherweise mehrere Berechtigungen hinzufügen müssen.
Funktionsbasierter Ansichts-Dekorator:
from django.contrib.auth.decorators import permission_required
@permission_required('catalog.can_mark_returned')
@permission_required('catalog.can_edit')
def my_view(request):
# …
Ein permission-required Mixin für klassenbasierte Ansichten.
from django.contrib.auth.mixins import PermissionRequiredMixin
class MyView(PermissionRequiredMixin, View):
permission_required = 'catalog.can_mark_returned'
# Or multiple permissions
permission_required = ('catalog.can_mark_returned', 'catalog.change_book')
# Note that 'catalog.change_book' is permission
# Is created automatically for the book model, along with add_book, and delete_book
Hinweis: Es gibt einen kleinen Standardunterschied im obigen Verhalten. Standardmäßig für einen angemeldeten Benutzer mit einer Berechtigungsübertretung:
@permission_required
leitet zum Login-Bildschirm weiter (HTTP-Status 302).PermissionRequiredMixin
gibt 403 zurück (HTTP-Status Forbidden).
Normalerweise möchten Sie das PermissionRequiredMixin
Verhalten: 403 zurückgeben, wenn ein Benutzer eingeloggt ist, aber nicht die richtige Berechtigung hat. Um dies für eine Funktionsansicht zu tun, verwenden Sie @login_required
und @permission_required
mit raise_exception=True
, wie gezeigt:
from django.contrib.auth.decorators import login_required, permission_required
@login_required
@permission_required('catalog.can_mark_returned', raise_exception=True)
def my_view(request):
# …
Beispiel
Wir werden die LocalLibrary hier nicht aktualisieren; vielleicht im nächsten Tutorial!
Stellen Sie sich der Herausforderung
Früher in diesem Artikel haben wir Ihnen gezeigt, wie man eine Seite für den aktuellen Benutzer erstellt, die die Bücher auflistet, die er ausgeliehen hat. Die Herausforderung besteht nun darin, eine ähnliche Seite zu erstellen, die nur für Bibliothekare sichtbar ist, die alle ausgeliehenen Bücher anzeigt und den Namen jedes Entleihers enthält.
Sie sollten dasselbe Muster wie bei der anderen Ansicht folgen können. Der Hauptunterschied besteht darin, dass Sie die Ansicht nur auf Bibliothekare beschränken müssen. Sie könnten dies basierend darauf tun, ob der Benutzer ein Mitarbeiter ist (Funktion-Dekorator: staff_member_required
, Templatevariable: user.is_staff
), aber wir empfehlen Ihnen stattdessen, die can_mark_returned
Berechtigung und PermissionRequiredMixin
zu verwenden, wie im vorherigen Abschnitt beschrieben.
Warnung: Denken Sie daran, Ihren Superuser nicht für Berechtigungstests zu verwenden (Berechtigungsprüfungen geben für Superuser immer true zurück, auch wenn eine Berechtigung noch nicht definiert wurde!). Erstellen Sie stattdessen einen Bibliothekar-Benutzer und fügen Sie die erforderliche Fähigkeit hinzu.
Wenn Sie fertig sind, sollte Ihre Seite ungefähr wie im folgenden Screenshot aussehen.
Zusammenfassung
Ausgezeichnete Arbeit — Sie haben jetzt eine Website erstellt, auf der sich Bibliotheksmitglieder einloggen und ihre eigenen Inhalte anzeigen können, und auf denen Bibliothekare (mit der richtigen Berechtigungen) alle ausgeliehenen Bücher und deren Entleiher anzeigen können. Im Moment betrachten wir immer noch nur Inhalte, aber dieselben Prinzipien und Techniken werden verwendet, wenn Sie anfangen möchten, Daten zu ändern und hinzuzufügen.
In unserem nächsten Artikel werden wir uns ansehen, wie Sie Django-Formulare verwenden können, um Benutzereingaben zu sammeln und dann einige unserer gespeicherten Daten zu ändern.
Siehe auch
- Benutzer-Authentifizierung in Django (Django-Dokumentation)
- Verwendung des (Standard) Django-Authentifizierungssystems (Django-Dokumentation)
- Einführung in klassenbasierte Ansichten > Dekorieren von klassenbasierten Ansichten (Django-Dokumentation)