1. 程式人生 > >Django 2.0 專案實戰 (3): 使用者重置密碼與退出登入

Django 2.0 專案實戰 (3): 使用者重置密碼與退出登入

在之前兩篇文章中我們擴充套件了Django自帶的User模型並實現了使用者的登入與註冊,並同時實現了檢視和編輯使用者個人資料的功能。本文是Django實現使用者註冊登入系列教程的最後一篇,我們將會開發兩個功能頁面,一個允許使用者在登入後重置密碼,一個是退出登入。本文程式碼用Django 2.0 + Python 3.X編寫。

第一步 重溫models.py和urls.py

# users/models.py

from django.db import models
from django.contrib.auth.models import User
# Create your models here.


class UserProfile(models.Model):

    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')

    org = models.CharField(
        'Organization', max_length=128, blank=True)

    telephone = models.CharField(
        'Telephone', max_length=50, blank=True)

    mod_date = models.DateTimeField('Last modified', auto_now=True)

    class Meta:
        verbose_name = 'User Profile'

    def __str__(self):
        return "{}".format(self.user.__str__())

如果你不知道下面URL的含義, 請點選這裡

# users/urls.py

from django.urls import re_path
from . import views

app_name = 'users'
urlpatterns = [
    re_path(r'^register/$', views.register, name='register'),
    re_path(r'^login/$', views.login, name='login'),
    re_path(r'^user/(?P<pk>\d+)/profile/$', views.profile, name='profile'),
    re_path(r'^user/(?P<pk>\d+)/profile/update/$', views.profile_update, name='profile_update'),
    re_path(r'^user/(?P<pk>\d+)/pwd_change/$', views.pwd_change, name='pwd_change'),
    re_path(r'^logout/$', views.logout, name='logout'),

第二步 編寫檢視views.py

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from .models import UserProfile
from django.contrib import auth
from django.conf import settings
from .forms import RegistrationForm, LoginForm, ProfileForm, PwdChangeForm
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required

@login_required
def logout(request):
    auth.logout(request)
    return HttpResponseRedirect("/accounts/login/")

@login_required
def pwd_change(request, pk):
    user = get_object_or_404(User, pk=pk)

    if request.method == "POST":
        form = PwdChangeForm(request.POST)

        if form.is_valid():

            password = form.cleaned_data['old_password']
            username = user.username

            user = auth.authenticate(username=username, password=password)

            if user is not None and user.is_active:
                new_password = form.cleaned_data['password2']
                user.set_password(new_password)
                user.save()
                return HttpResponseRedirect("/accounts/login/")

            else:
                return render(request, 'users/pwd_change.html', {'form': form,
        'user': user, 'message': 'Old password is wrong. Try again'})
    else:
        form = PwdChangeForm()

    return render(request, 'users/pwd_change.html', {'form': form, 'user': user})

views.logout非常好理解。我們重點看下views.pwd_change函式是怎麼工作的:

  • 首先我們用@login_required裝飾器確定使用者是否已經登入,只有登入的才能修改個人密碼。後面我們會專文介紹裝飾器的用法。

  • 我們先從url獲取user的主鍵pk(id), 利用get_object_or_404方法獲取需要修改密碼的使用者物件user

  • 當用戶通過POST方法提交密碼修改表單,我們先驗證表單PwdChangeForm的資料是否有效。如果老的密碼是正確的,我們將更新過的密碼通過set_password方法資料存入user。修改密碼成功後返回登入頁面。

  • 如果使用者沒有提交表單或不是通過POST方法提交表單,我們生成一張空的PwdChangForm

PwdChangeForm包括了老密碼,新密碼和密碼確認3個欄位。我們通過form類自帶的clean方法在表單裡添加了表單驗證。要對form裡哪個欄位進行驗證,你自需要定義一個clean_欄位名方法。在這個案例裡我們需要新密碼滿足一定長度要求,同時還要求使用者兩次輸入密碼是一致的。

# users/forms.py
class PwdChangeForm(forms.Form):

    old_password = forms.CharField(label='Old password', widget=forms.PasswordInput)

    password1 = forms.CharField(label='New Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)

    # Use clean methods to define custom validation rules

    def clean_password1(self):
        password1 = self.cleaned_data.get('password1')

        if len(password1) < 6:
            raise forms.ValidationError("Your password is too short.")
        elif len(password1) > 20:
            raise forms.ValidationError("Your password is too long.")

        return password1

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Password mismatch. Please enter again.")

        return password2

第三步 編寫template

#users/templates/users/pwd_change.html

{% block content %}
<h2>Change Password</h2>
{% if message %}
 {{ message }}
{% endif %}
<div class="form-wrapper">
   <form method="post" action="" enctype="multipart/form-data">
      {% csrf_token %}
      {% for field in form %}
           <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
             <p class="help">{{ field.help_text|safe }}</p>
        {% endif %}
           </div>
        {% endfor %}
      <div class="button-wrapper submit">
         <input type="submit" value="Submit" />
      </div>
   </form>
    <a href="/accounts/logout/">Logout</a>
</div>
{% endblock %}

本文介紹瞭如何利用Django 2.0實現使用者密碼重置和退出登入的方法。整個使用者註冊和登入還是太簡單了,比如沒有郵箱驗證,也不能通過第三方APP授權登入,介面也比較醜陋。一個更好的方式是使用已經成熟的第三方Django Package比如django-allauth來實現使用者註冊和登入。