Django搭建個人部落格--使用者的登入和登出

貝勒裡恩 發表於 2020-11-22

一、分析

在Django中用app來區分不同功能的模組,達到程式碼隔離和複用。因為使用者管理和部落格文章的功能不能,因此需要新建一個專門的app。

進入虛擬環境,執行startapp指令建立新的app

python manage.py startapp userprofile

app建立完之後還需要app配置:

1、開啟my_blog/urls.py,加入userprofile使用者模組的路由分發

urlpatterns = [
    path('admin/', admin.site.urls),

    # 新增程式碼,配置app的url
    path('article/', include('article.urls', namespace='article')),

    # 使用者管理
    path('userprofile/', include('userprofile.urls', namespace='userprofile')),
    
]

2、開啟my_blog/settings.py,註冊app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 新增'article'程式碼,啟用app
    'article',
    'userprofile',
]

二、建立表單

使用者登入時,需要填寫賬戶密碼等表單資料,因此又要用到Form表單類。

userprofile目錄中建立表單類的檔案forms.py,編寫如下程式碼

# 引入表單類
from django import forms
# 引入User模型
from django.contrib.auth.models import User

# 登入表單,繼承了forms.Form類
class UserLoginForm(forms.Form):
	username = forms.CharField()
	password = forms.CharField()

在前面發表文章的模組中,表單類繼承了forms.ModelForm,這個父類適合於需要直接與資料庫互動的功能,比如新建、更新資料庫的欄位等。如果表單將使用者直接新增或編輯Django模型,則可以使用ModelForm來避免重複書寫欄位描述。

forms.Form則需要手動配置每個欄位,它適用於不與資料庫進行直接互動的功能。使用者登入不需要對資料庫進行任何改動,因此直接繼承forms.Form就可以了。


三、編寫檢視

使用者的登入是比較複雜的功能,好在Django提供了封裝好的模組供我們使用。

userprofile/views.py中寫檢視函式

from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from .forms import UserLoginForm

def user_login(request):
	if request.method == 'POST':
		user_login_form = UserLoginForm(data=request.POST)
		if user_login_form.is_valid():
			# .cleaned_data 清洗出合法資料
			data = user_login_form.cleaned_data
			# 檢驗賬號、密碼是否正確匹配資料庫中的某個使用者
			# 如果均匹配則返回這個user物件
			user = authenticate(username=data['username'],password=data['password'])
			if user:
				# 將使用者資料存在session中,即實現了登入動作
				login(request,user)
				return redirect("article:article_list")
			else:
				return	HttpResponse("賬號或密碼輸入有誤,請重新輸入~")

		else:
			return HttpResponse("賬號或密碼不合法")
	elif request.method == 'GET':
		user_login_form = UserLoginForm()
		context = {'form': user_login_form}
		return render(request, 'userprofile/login.html',context)

	else:
		return HttpResponse("請使用GET或POST請求資料")

  • 跟發表文章的表單類類似,Form物件的主要任務就是驗證資料。呼叫is_valid()方法驗證並返回指定資料是否有效的布林值;
  • Form不僅負責驗證資料,還可以“清洗”它:將其標準化為一致的格式,這個特性使得它允許以各種方式輸入特定欄位的資料,並且始終產生一致的輸出。一但Form使用資料建立了一個例項並對其進行了驗證,就可以通過cleaned_data屬性訪問清洗之後的資料;
  • authenticate()方法驗證使用者名稱稱和密碼是否匹配,如果是,則將這個使用者資料返回;
  • login()方法實現使用者登入,將使用者資料儲存在session中;

Session在網路應用中,稱為“會話控制”,它儲存特定使用者會話所需的屬性即配置資訊。
當使用者在Web頁之間跳轉時,儲存在Session物件中的變數將不會丟失,而是在整個使用者會話中一直存在下去;
Session最常見的用法就是儲存使用者的登入資料;


四、編寫登入模板

建立templates/userprofile/login.html模板

{% extends "base.html" %} {% load staticfiles %}
{% block title %} 登入 {% endblock title %}

{% block content %}
<div class="container">
	<div class="row">
		<div class="col-12">
			<br>
			<form method="post" action=".">
				{% csrf_token %}
				<!-- 賬號 -->
				<div class="form-group">
					<label for="username">賬號</label>
					<input type="text" class="form-control" id="username" name="username">
				</div>
				<!-- 密碼 -->
				<div class="form-group">
					<label for="password">密碼</label>
					<input type="password" class="form-control" id="password" name="password">
				</div>
				<!-- 提交按鈕 -->
				<button type="submit" class="btn btn-primary">提交</button>
			</form>
		</div>
	</div>
</div>
{% endblock content%}
  • type="password"可以讓輸入密碼的時候顯示小圓點,避免有人偷窺;

五、增加登入入口

改寫templates/header.html,把登入的按鈕加進行

<!-- 導航入口 -->
	<div>
    	<ul class="navbar-nav">
        	<!-- 條目 -->
            <li class="nav-item">
            	<a class="nav-link" href="{% url 'article:article_create' %}">寫文章</a>
            </li>
            <li class="nav-item">
            	<a class="nav-link" href="{% url 'article:article_list' %}">文章</a>
            </li>

            <!-- Django的if模板語句 -->
            {% if user.is_authenticated %}
            <li class="nav-item dropdown">
            	<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                            {{ user.username }}</a>
                <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                	<a class="dropdown-item" href="{% url 'userprofile:logout' %}">退出登入</a>
                </div>
            </li>
            <!-- 如果使用者未登入,則顯示登入 -->
            {% else %}
	        <li class="nav-item">
            	<a class="nav-link" href="{% url 'userprofile:login' %}">登入</a>
            </li>
            <!-- if語句在這裡結束 -->
            {% endif %}

	</ul>
</div>

這裡使用的新的模板語法:{% if … %},來判斷使用者是否已經登入:

  • 如果使用者已經登入,則顯示一個名字為使用者名稱稱的下拉框,就行通常的社交網站一樣;
  • 如果使用者未登入,則顯示“登入”兩個字提醒使用者可以點選登入;

is_authenticatedmodels.User類的屬性,用於判斷使用者是否已通過身份驗證。


六、路由配置

建立userprofile/urls.py檔案,並寫入如下程式碼

from django.urls import path
from . import views

app_name = 'userprofile'

urlpatterns = [
	# 使用者登入
	path('login/', views.user_login, name='login'),
	
]

七、使用者的退出

1、開啟userprofile/views.py新增使用者退出的檢視

...
from django.contrib.auth import authenticate, login, logout

...

# 使用者退出
def user_logout(request):
	logout(request)
	return redirect("article:article_list")

2、開啟userprofile/urls.py進行路由配置

urlpatterns = [
	# 使用者登入
	path('login/', views.user_login, name='login'),
	# 使用者退出
	path('logout/', views.user_logout, name="logout"),
]

3、退出登入入口
在寫登入的程式碼時,已經給使用者退出留好了介面,因此只需要改動templates/header.html

...
	<!-- 如果使用者未登入,則顯示登入 -->
    {% else %}
    	<li class="nav-item">
    		<a class="nav-link" href="{% url 'userprofile:login' %}">登入</a>
    	</li>
    <!-- if語句在這裡結束 -->
    {% endif %}

八、檢視效果

在這裡插入圖片描述


在這裡插入圖片描述


在這裡插入圖片描述