HOWTO · Django

Django Passwort ändern

Wir werden mit dieser Erklärung lernen, wie wir eine Webseite erstellen, auf der der Benutzer das Passwort nach der Anmeldung auf der Webseite in Django ändern kann.

Auf dieser Seite

Djangos integrierte PasswordChangeView ermöglicht angemeldeten Benutzern, das Passwort ihres aktuellen Kontos zu ändern. Das unterscheidet sich von einem Verfahren zum Zurücksetzen des Passworts, mit dem Benutzer ohne ihr aktuelles Passwort wieder Zugriff erhalten. Die folgende Implementierung verbindet das Formular, die Erfolgsseite, die URL-Namen und einen Link von der Startseite.

Passwortänderungsansichten einrichten

Leiten Sie in users/views.py eine Klasse von Djangos PasswordChangeView ab und geben Sie ihr den Pfad zum Formular-Template. Legen Sie success_url mit reverse_lazy fest, damit Django das benannte Ziel auflöst, sobald die URL-Konfiguration geladen ist. Verwenden Sie für die Abschlussseite PasswordChangeDoneView; PasswordResetDoneView ist für das Zurücksetzen von Passwörtern vorgesehen.

Dieser eigenständige Konfigurations-Harness verwendet einfache Stellvertreter für Django. So lassen sich Namen und Verknüpfungen auch ohne Django-Projekt nachvollziehen. Übernehmen Sie in Ihrem Projekt die Importe und Anwendungsdefinitionen, lassen Sie aber die Harness-Einrichtung und die abschließenden Assertions weg. Djangos Passwortänderungsformular prüft das eingegebene aktuelle Passwort und die Bestätigung des neuen Passworts anhand der konfigurierten Passwortvalidatoren.

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

# Harness only: stand-ins let this configuration run without Django installed.
import sys
import types

django = types.ModuleType("django")
contrib = types.ModuleType("django.contrib")
auth = types.ModuleType("django.contrib.auth")
auth_views = types.ModuleType("django.contrib.auth.views")
urls = types.ModuleType("django.urls")
django.__path__ = []
contrib.__path__ = []
auth.__path__ = []

class View:
    @classmethod
    def as_view(cls):
        return cls

class PasswordChangeView(View):
    pass

class PasswordChangeDoneView(View):
    pass

def reverse_lazy(name):
    return name

def path(route, view, name=None):
    return (route, view, name)

def include(module, namespace=None):
    return (module, namespace)

auth_views.PasswordChangeView = PasswordChangeView
auth_views.PasswordChangeDoneView = PasswordChangeDoneView
urls.reverse_lazy = reverse_lazy
urls.path = path
urls.include = include
sys.modules.update({
    "django": django,
    "django.contrib": contrib,
    "django.contrib.auth": auth,
    "django.contrib.auth.views": auth_views,
    "django.urls": urls,
})

users_views = types.ModuleType("users_views")
users_views.ChangePasswordView = None
users_views.ChangePasswordDoneView = None
sys.modules["users_views"] = users_views

# users/views.py
from django.contrib.auth.views import PasswordChangeDoneView, PasswordChangeView
from django.urls import reverse_lazy

class ChangePasswordView(PasswordChangeView):
    template_name = "users/password-change.html"
    success_url = reverse_lazy("users:password-change-done")

class ChangePasswordDoneView(PasswordChangeDoneView):
    template_name = "users/password-change-done.html"

users_views.ChangePasswordView = ChangePasswordView
users_views.ChangePasswordDoneView = ChangePasswordDoneView

# users/urls.py
# In the project file, import these classes from .views.
from django.urls import path
from users_views import ChangePasswordDoneView, ChangePasswordView

app_name = "users"
urlpatterns = [
    path("change-password/", ChangePasswordView.as_view(), name="password-change"),
    path("change-password/done/", ChangePasswordDoneView.as_view(), name="password-change-done"),
]

# project urls.py
from django.urls import include, path

project_urlpatterns = [
    path("users/", include("users.urls", namespace="users")),
]

assert ChangePasswordView.success_url == "users:password-change-done"
assert [route[2] for route in urlpatterns] == ["password-change", "password-change-done"]
assert project_urlpatterns[0][1] == ("users.urls", "users")

In Ihrem Projekt importiert die URL-Datei der App die Ansichten mit from .views import ChangePasswordDoneView, ChangePasswordView; der Harness verwendet users_views, damit das Beispiel in einem eigenständig ausführbaren Block bleibt. Importieren Sie in der URL-Datei des Projekts include und path aus django.urls und verwenden Sie dieselbe im Harness gezeigte Konfiguration: path("users/", include("users.urls", namespace="users")).

App- und Projekt-URL-Muster registrieren

Der obige Harness enthält beide URL-Ebenen. Legen Sie im Projekt in users/urls.py app_name = "users" fest und binden Sie dieses Modul in die URL-Konfiguration des Projekts mit namespace="users" ein. Zusammen sorgen diese Definitionen dafür, dass users:password-change-done aufgelöst werden kann. Die Routennamen der App und das Ziel reverse_lazy müssen übereinstimmen.

Templates für Passwortänderung und Abschlussseite erstellen

Erstellen Sie users/templates/users/password-change.html und erweitern Sie darin Ihr gemeinsames base.html. Dieses Template sendet das Formular an dieselbe URL, enthält {% csrf_token %} und gibt mit {{ form.as_p }} die Felder für das aktuelle und das neue Passwort aus. Das CSRF-Token unterstützt Djangos Schutz vor gefälschten Anfragen; es ersetzt weder die Authentifizierung noch die Passwortprüfung.

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

{% extends 'base.html' %}

{% block title %}Change password{% endblock title %}

{% block content %}
<h1>Change your password</h1>
<form action="" method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Change password</button>
</form>
{% endblock content %}

Erstellen Sie users/templates/users/password-change-done.html für die Erfolgsantwort. Erweitern Sie dasselbe Basistemplate, bestätigen Sie darin die Passwortänderung und verlinken Sie zurück zur Route home-view des Projekts. Nach einem erfolgreichen POST wird auf diese Seite weitergeleitet; das bloße Anzeigen der Seite ändert kein Passwort.

{% extends 'base.html' %}

{% block title %}Password changed{% endblock title %}

{% block content %}
<h1>Your password has been changed</h1>
<a href="{% url 'home-view' %}">Home page</a>
{% endblock content %}

Fügen Sie im Startseiten-Template mit {% url 'users:password-change' %} einen Link zum Formular ein. Djangos integrierte Passwortänderungsansicht setzt eine Anmeldung voraus. Platzieren Sie den Link daher in der Navigation für angemeldete Benutzer oder lassen Sie die Ansicht nicht angemeldete Besucher weiterleiten.

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

<a href="{% url 'users:password-change' %}">Change password</a>

Passwortänderung ausführen und überprüfen

Starten Sie das Projekt wie üblich in der Entwicklungsumgebung, melden Sie sich mit einem Testkonto an und folgen Sie dem neuen Link auf der Startseite. Geben Sie das aktuelle Passwort sowie ein gültiges, übereinstimmendes Paar neuer Passwörter ein. Prüfen Sie, ob Django zur Abschlussseite weiterleitet. Melden Sie sich anschließend ab und mit dem neuen Passwort wieder an. Dies ist eine Anleitung zur manuellen Überprüfung und kein Bericht darüber, dass der Ablauf in der Umgebung dieses Artikels ausgeführt wurde.

Eine kurze Prüfung der Routennamen veranschaulicht den Zusammenhang zwischen Namespace und Route:

Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.

app_name = "users"
route_name = "password-change-done"
success_target = f"{app_name}:{route_name}"
print(success_target)

Häufige Einrichtungsfehler beheben

Meldet Django, dass users:password-change-done nicht aufgelöst werden kann, prüfen Sie, ob app_name, der Namespace beim Einbinden in das Projekt, der name der Route und das Ziel reverse_lazy zusammenpassen. Ein Fehler vom Typ TemplateDoesNotExist bedeutet meist, dass der im View angegebene Template-Pfad nicht mit dem Speicherort unter templates/users/ in der App übereinstimmt. Prüfen Sie die Schreibweise und stellen Sie sicher, dass die App installiert ist, damit Django ihre Templates findet.

Meldet das Formular einen CSRF-Fehler, muss {% csrf_token %} innerhalb des POST-Formulars stehen. Stellen Sie außerdem sicher, dass die Seite über den normalen Anfrageablauf von Django übermittelt wird. Wird ein Besucher zur Anmeldeseite weitergeleitet, ist das bei dieser Funktion für angemeldete Benutzer erwartungsgemäß; melden Sie sich vor dem Test der Passwortänderung an. Wird die Abschlussseite angezeigt, ohne dass das Passwort erfolgreich geändert wurde, prüfen Sie, ob das Formular an die Ansicht gesendet wird und ob das eingegebene aktuelle Passwort sowie die Bestätigung des neuen Passworts den Validatoren des Projekts entsprechen.