圖書管理

定義圖書資料表

開啟應用程式 book 的資料模型定義檔 library/book/models.py,將內容修改如下:

from django.db.models import * # Create your models here. # 圖書 class Book(Model): title = CharField('書名', max_length=255) author = CharField('作者', max_length=255) publisher = CharField('出版社', max_length=255) preface = ImageField('封面圖片') def __str__(self): return "{}: {}".format(self.author, self.title)

在圖書的資料模型中設計了一個存放封面圖片的欄位,型態是 ImageField,它需要依賴 python 的 Pillow 函式庫,記得要先在終端機下使用 pip install Pillow 指令來安裝所需的函式庫。

修改過 models.py 之後,記得執行以下指令以套用到資料庫:

python manage.py makemigrations python manage.py migrate

開啟網站服務

python manage.py runserver 0.0.0.0:80

修改網站存取路徑規則

修改網站路徑規則檔 library/library/urls.py,新增第 23, 24 行規則:

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

定義應用程式的路徑規則

關於圖書管理,預計提供圖書列表、新增、查看、編輯、刪除等功能。請新增應用程式 book 的路徑規則檔案 library/book/urls.py,內容如下:

from django.urls import path from .views import * urlpatterns = [ path('', BookList.as_view(), name='book_list'), path('add/', BookAdd.as_view(), name='book_add'), path('<int:pk>/', BookView.as_view(), name='book_view'), path('<int:pk>/edit/', BookEdit.as_view(), name='book_edit'), path('<int:pk>/delete/', BookDelete.as_view(), name='book_delete'), ]

定義圖書管理相關處理視圖

接下來再進行功能的處理視圖的實作,請開啟 library/book/views.py,修改為以下程式碼:

from django.urls import reverse, reverse_lazy from django.views.generic import * from django.contrib.auth.mixins import LoginRequiredMixin from .models import * # Create your views here. class BookList(LoginRequiredMixin, ListView): # 圖書列表 model = Book paginate_by = 10 class BookView(LoginRequiredMixin, DetailView): # 檢視圖書 model = Book class BookAdd(LoginRequiredMixin, CreateView): # 新增圖書 model = Book fields = '__all__' template_name = 'form.html' success_url = reverse_lazy('book_list') class BookEdit(LoginRequiredMixin, UpdateView): # 編輯圖書 model = Book fields = '__all__' template_name = 'form.html' success_url = reverse_lazy('book_list') class BookDelete(LoginRequiredMixin, DeleteView): # 刪除圖書 model = Book template_name = 'confirm_delete.html' success_url = reverse_lazy('book_list')

建立書籍相關頁面範本

導覽列頁面範本

修改檔案 library/templates/navbar.html,加入第 13 - 17 行圖書列表的連結:

<!-- Navbar begin //--> <nav class="navbar navbar-expand-md navbar-dark bg-info mb-2"> <!-- 網站標誌 --> <div class="navbar-brand">圖書借閱系統</div> <!-- 在小螢幕的設備上顯示可展開/收合導覽選單的按鈕 --> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"> <span class="navbar-toggler-icon"></span> </button> <!-- 導覽列選單內容(可收合) --> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> {% if user.is_authenticated %} <li class="nav-item"> <a href="{% url 'book_list' %}" class="nav-link"> <i class="fas fa-book"></i> 圖書列表 </a> </li> <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 //-->

共用的表單範本

新增共用的表單範本檔 library/templates/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 type="submit" value="送出" /> </form> <script> var inputs = document.querySelectorAll('table input, table select, table textarea'); inputs.forEach(function(item) { item.classList.add('form-control'); }); </script> {% endblock %}

圖書列表範本

建立目錄 library/templates/book,再新增圖書列表頁面範本 library/templates/book/book_list.html

{% extends "base.html" %} {% block content %} <div class="mb-1"> <a href="{% url 'book_add' %}" class="btn btn-sm btn-primary"> <i class="fas fa-plus"></i> 新增圖書 </a> </div> <div id="book-list" class="card-group"> {% for book in book_list %} <div class="card shadow-sm"> <a href="{% url 'book_view' book.id %}"> <img src="{{ book.preface.url }}" alt="{{ book.title }}" class="card-img"> </a> <div class="card-body"> <div class="card-title"> <a href="{% url 'book_view' book.id %}">{{ book.title }}</a> </div> <div class="card-text">{{ book.author }}</div> </div> </div> {% endfor %} </div> {% include "pagination.html" %} {% endblock %}

請先建立 library/static/css 資料夾,再新增 library/static/css/custom.css,於其中撰寫自訂的 css 規則來調整外觀:

#book-list .card-body { padding: 5pt; font-size: 11pt; justify-content: space-between; display: flex; flex-direction: column; } #book-list .card { flex: 0 0 20%; }

還要處理分頁的問題,請新增分頁控制項的範本檔 library/templates/pagination.html,你可以直接複製先前案例的範本檔來用。

圖書檢視範本

新增圖書檢視頁面範本檔案 library/temapltes/book/book_detail.html

{% extends "base.html" %} {% block content %} <div class="mb-2"> <a href="{% url 'book_edit' book.id %}" class="btn btn-sm btn-primary"> <i class="fas fa-edit"></i> 修改 </a> <a href="{% url 'book_delete' book.id %}" class="btn btn-sm btn-danger"> <i class="fas fa-trash"></i> 刪除 </a> </div> <div id="book-detail" class="row"> <div class="col-md-4"> <img src="{{ book.preface.url }}" alt="{{ book.title }}"> </div> <div class="col-sm-8"> <div class="card"> <div class="card-header">{{ book.title }}</div> <table class="table"> <tr> <th>作者</th><td>{{ book.author }}</td> </tr> <tr> <th>出版社</th><td>{{ book.publisher }}</td> </tr> </table> </div> </div> </div> {% endblock %}

library/static/css/custom.css 新增以下規則組:

#book-detail img { box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.3); width: 100%; }

共用的確認刪除範本

新增範本檔案 library/templates/confirm_delete.html

{% extends "base.html" %} {% block content %} <p class="alert alert-danger"> 確定要刪除這筆紀錄嗎? <br/> {{ object }} </p> <form action="" method="post"> {% csrf_token %} <input type="submit" class="btn btn-danger" value="是的,我要刪除"> </form> {% endblock %}