新增行政人員帳號

我們可以運用 Django 內建的後臺管理系統來進行人員帳號的管理與維護,只要存取專案網站的 /admin/ 路徑,以初始建立的管理員帳號登入後,即可透過內建的管理程式管理人員帳號。

不過也可以自行撰寫處理程式,資料模型的部份可以直接使用預統預設的定義,搭配我們自行定義路徑規則、視圖以及頁面範本,以便與我們的專案網站整合得更一致。

我們將在專案中另行創建一支應用程式專責處理人員帳號的維護,把報修項目與人員帳號的處理分開,當然也可以直接在應用程式 log 中撰寫相關程式碼就好,端看個人喜好。

新增應用程式

開啟命令提示字元或終端機,透過專案管理腳本 manage.py 來創建新的應用程式:

python manage.py startapp staff

修改專案設定檔 repair/repair/settings.py,將新增的應用程式加入專案:

# Application definition INSTALLED_APPS = [ 'log', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'staff', ]

資料模型

內建的應用程式 django.contrib.auth 已經定義好資料模型 User 了,直接套用就好,不需要自行定義。

路徑規則

新增應用程式 staff 的路徑規則檔 repair/staff/urls.py

from django.urls import path from .views import * urlpatterns = [ # 行政人員帳號列表 path('', StaffList.as_view(), name='staff_list'), # 新增行政人員帳號 path('new/', StaffNew.as_view(), name='staff_new'), # 修改行政人員資料 path('<int:pk>/update/', StaffUpdate.as_view(), name='staff_update'), # 修改行政人員密碼 path('<int:pk>/passwd/', StaffPasswd.as_view(), name='staff_passwd'), ]

記得修改專案的路徑規則檔,將自訂應用程式 staff 的路徑規則加入整個專案。請修改 repair/repair/urls.py

urlpatterns = [ path('admin/', admin.site.urls), path('log/', include('log.urls')), path('', RedirectView.as_view(url='log/')), path('accounts/', include('django.contrib.auth.urls')), path('staff/', include('staff.urls')), ]

視圖

在之前的例子中,對於權限管控,只很簡單地繼承 LoginRequiredMixin 來檢查使用者是否為登入的狀態才允許操作某些功能。不過在這個例子中,這個專案網站可能會開放給其他行政人員使用,所以應該要使用更進階的權限管理方式,否則只要登入後,每個人都可以新增/修改帳號,這就有點恐怖了。

Django 也有內建的基本的權限管控功能,可以為各別帳號針對每個資料模型指定 4 種存取權限 viewaddchangedelete。如果要針對應用程式 foo 所定義的資料模型 bar 的話,其相對應的權限名稱為:

了解 Django 內建的基本權限管控方式後,就可以採用 PermissionRequiredMixin 這個混成類別來協助通用視圖檢查使用者是否具備指定的權限。

repair/staff/views.py 修改為以下內容:

from django.shortcuts import render from django.views.generic import * from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.models import User from django.urls import reverse # Create your views here. # 行政人員列表 class StaffList(PermissionRequiredMixin, ListView): permission_required = 'auth.view_user' model = User ordering = ['username'] paginate_by = 15 # 新增行政人員帳號 class StaffNew(PermissionRequiredMixin, CreateView): permission_required = 'auth.add_user' model = User fields = ['username', 'first_name', 'password'] def get_success_url(self): return reverse('staff_list') # 表單驗證 def form_valid(self, form): user = form.save(commit=False) user.set_password(form.cleaned_data['password']) return super().form_valid(form) # 修改行政人員帳號資料 class StaffUpdate(PermissionRequiredMixin, UpdateView): permission_required = 'auth.change_user' model = User fields = ['username', 'first_name'] def get_success_url(self): return reverse('staff_list') # 修改行政人員密碼 class StaffPasswd(PermissionRequiredMixin, UpdateView): permission_required = 'auth.change_user' model = User fields = ['password'] def get_success_url(self): return reverse('staff_list') # 設定初始值 def get_initial(self): return { 'password': '', } # 表單驗證 def form_valid(self, form): user = form.save(commit=False) user.set_password(form.cleaned_data['password']) return super().form_valid(form)

頁面範本

新增 repair/staff/templatesrepair/staff/templates/auth 兩個資料夾

使用者帳號列表

新增頁面範本 repair/staff/templates/auth/user_list.html,將其內容設定如下:

{% extends 'base.html' %} {% block content %} {% if perms.auth.add_user %} <a href="{% url 'staff_new' %}" class="btn btn-sm btn-primary"> 新增帳號 </a> {% endif %} <table class="table table-sm mt-1"> <thead> <tr> <th>帳號</th> <th>姓名</th> {% if perms.auth.change_user %} <th>功能</th> {% endif %} </tr> </thead> <tbody> {% for user in user_list %} <tr> <td>{{ user.username }}</td> <td>{{ user.first_name }}</td> {% if perms.auth.change_user %} <td> <a href="{% url 'staff_update' user.id %}" class="btn btn-sm btn-primary">修改</a> <a href="{% url 'staff_passwd' user.id %}" class="btn btn-sm btn-primary">密碼</a> </td> {% endif %} </tr> {% endfor %} </tbody> </table> {% include 'pagination.html' %} {% endblock %}

帳號編輯表單

新增使用者帳號、修改使用者帳號以及修改使用者密碼時,預設會使用同一個頁面範本檔 user_form.html,請新增 repair/staff/templates/auth/user_form.html,並將其內容設定如下:

{% extends "base.html" %} {% block content %} <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <table class="table table-sm"> {{ form.as_table }} </table> <input class="btn btn-primary" type="submit" value="送出" /> </form> <script> // 取得表格內的所有輸入元件(<input>與<textarea>) var inputs = document.querySelectorAll('table input, table textarea'); inputs.forEach(function(item) { // 為每一個輸入元件新增套用 form-control 類別 item.classList.add('form-control'); }); </script> {% endblock %}

新增使用者帳號

修改使用者帳號

修改使用者密碼

導覽列

開啟導覽列範本檔 repair/log/templates/navbar.html,修改如下:

<!-- Navbar begin //--> <nav class="navbar navbar-expand-sm navbar-light bg-light mb-4 shadow-sm"> <!-- 網站標誌 --> <div class="navbar-brand"> <i class="fas fa-wrench"></i> 線上報修系統 </div> <!-- 在小螢幕的設備上顯示可展開/收合導覽選單的按鈕 --> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <!-- 導覽列選單內容(可收合) --> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav ml-auto nav-pills"> <li class="nav-item"> <a href="{% url 'log_list' %}" class="nav-link"> <i class="fas fa-list-alt"></i> 報修記錄 </a> </li> <li class="nav-item"> <a href="{% url 'log_create' %}" class="nav-link"> <i class="fas fa-edit"></i> 我要報修 </a> </li> {% if user.is_authenticated %} {% if perms.auth.view_user %} <li class="nav-item"> <a href="{% url 'staff_list' %}" class="nav-link"> <i class="fas fa-users"></i> 行政人員 </a> </li> {% endif %} <li class="nav-item"> <a href="{% url 'logout' %}" class="nav-link"> <i class="fas fa-sign-out-alt"></i> 登出 {{ user.username }} </a> </li> {% else %} <li class="nav-item"> <a href="{% url 'login' %}" class="nav-link"> <i class="fas fa-sign-in-alt"></i> 登入 </a> </li> {% endif %} </ul> </div> </nav> <!-- Navbar end //-->