建立資料庫與表單
修改 repair/log/models.py
:
from django.db import models
class LogItem(models.Model):
ST_OPTIONS = [
(0, '待處理'),
(1, '處理中'),
(2, '已結案'),
]
subject = models.CharField('報修主旨', max_length=255)
description = models.TextField('報修內容')
reporter = models.CharField('報修人', max_length=30)
phone = models.CharField('聯絡電話', max_length=30)
ctime = models.DateTimeField('報修時間', auto_now_add=True)
handler = models.CharField('處理人員', max_length=30)
status = models.IntegerField(
'處理進度',
default=0,
choices=ST_OPTIONS
)
comment = models.TextField('處理說明')
utime = models.DateTimeField('更新時間', auto_now=True)
def __str__(self):
return self.subject
python manage.py makemigrations
python manage.py migrate
另外,在第一次進行資料庫遷移時,記得以專案管理腳本的 createsuperuser
參數來建立管理員帳號:
python manage.py createsuperuser
接下來就可以將專案網站服務執行起來,以便在開發過程中進行測試:
python manage.py runserver 0.0.0.0:80
決定好路徑與功能的對應關係之後,先修改專案的路徑規則檔 repair/repair/urls.py
:
from django.contrib import admin
from django.urls import path, include
from django.views.generic import RedirectView
urlpatterns = [
path('admin/', admin.site.urls),
path('log/', include('log.urls')),
path('', RedirectView.as_view(url='log/')),
]
接著就將焦點放在應用程式 log
上,先來定義它自己的路徑規則。請新增檔案 repair/log/urls.py
:
from django.urls import path
from .views import *
urlpatterns = [
path('', LogList.as_view(), name='log_list'),
path('create/', LogCreate.as_view(), name='log_create'),
path('<int:pk>/', LogView.as_view(), name='log_view'),
path('<int:pk>/reply/', LogReply.as_view(), name='log_reply'),
]
定義處理視圖
接著來撰寫每條路徑規則相對應的處理視圖,請開啟 repair/log/views.py
,修改為以下程式碼:
from django.shortcuts import render
from django.views.generic import *
from django.urls import reverse
from .models import LogItem
class LogList(ListView):
model = LogItem
ordering = ['-id']
class LogView(DetailView):
model = LogItem
class LogCreate(CreateView):
model = LogItem
fields = ['subject', 'description', 'reporter', 'phone']
def get_success_url(self):
return reverse('log_list')
class LogReply(UpdateView):
model = LogItem
fields = ['handler', 'status', 'comment']
def get_success_url(self):
return reverse('log_view', kwargs={'pk': self.object.id})
頁面範本
網站基底頁面範本
建立放置頁面範本的資料夾 repair/log/templates
以及 repair/log/templates/log
。
為了維持專案網站外觀的一致性,先新增網站基底範本 repair/log/templates/base.html
,並引入 Bootstrap CSS 框架與 FontAwesome 框架:
<!doctype html>
<html lang="zh-hant">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
<title>線上報修系統</title>
</head>
<body>
<div class="container">
{% include "navbar.html" %}
{% block content %}{% endblock %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
</body>
</html>
新增導覽列範本檔 repair/log/templates/navbar.html
:
<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>
</ul>
</div>
</nav>
報修記錄列表
建立報修記錄列表範本檔 repair/log/templates/log/logitem_list.html
:
{% extends 'base.html' %}
{% block content %}
<table class="table table-sm table-hover">
<thead>
<tr>
<th>報修時間</th>
<th>報修主旨</th>
<th>報修人</th>
<th>狀態</th>
<th>更新時間<th>
</tr>
</thead>
<tbody>
{% for item in logitem_list %}
<tr>
<td>{{ item.ctime }}</td>
<td>
<a href="{{ item.id }}">{{ item.subject }}</a>
</td>
<td>{{ item.reporter }}</td>
<td>{{ item.get_status_display }}</td>
<td>{{ logitem.utime }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
新增報修記錄
建立新增報修記錄範本檔 repair/log/templates/log/logitem_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>
{% endblock %}
</form>
<script>
var inputs = document.querySelectorAll('table input, table textarea');
inputs.forEach(function(item) {
item.classList.add('form-control');
});
</script>
{% endblock %}
檢視報修記錄
新增檔案 repair/log/temapltes/web/logitem_detail.html
{% extends "base.html" %}
{% block content %}
<div class="card">
<div class="card-header">
<div class="h3">{{ content.subject }}</div>
</div>
<div class="card-body">
<div class="card-text">
{{ content.description|linebreaks }}
</div>
</div>
<div class="card-footer card-text d-flex justify-content-between text-muted">
<small title="報修人"><i class="fas fa-user"></i> {{ content.reporter }} <i class="fas fa-phone"></i> {{ content.phone }}</small>
<small><i class="far fa-clock"></i> {{ content.publication_date }}</small>
</div>
</div>
<hr>
<div class="card mt-3">
<div class="card-header d-flex justify-content-between">
<div class="h3">處理狀況說明</div>
<div>{{ content.get_status_display }}</div>
</div>
<div class="card-body">{{ content.comment|linebreaks }}</div>
<div class="card-footer card-text d-flex justify-content-between text-muted">
<small title="處理人員"><i class="fas fa-user-md"></i> {{ content.handler }}</small>
<small><i class="far fa-clock"></i> {{ content.handle_date }}</small>
</div>
</div>
{% endblock %}
分頁顯示
在報修項目列表的頁面中,當系統上線時間一長,累積的報修事項過多時,一般都會採用分頁顯示的方式來顯示列表,避免在列表頁面上顯示過多資料。
開啟 repair/log/views.py
,修改 LogList
:
class LogList(ListView):
model = LogItem
ordering = ['-id']
paginate_by = 15
新增分頁控制項範本 repair/log/templates/pagination.html
:
{% if is_paginated %}
{% with btn_class="btn btn-sm btn-outline-primary" %}
<div>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}" class="{{ btn_class }}">
<i class="fas fa-chevron-circle-left"></i>上一頁
</a>
{% endif %}
{% for page in paginator.page_range %}
{% if page == page_obj.number %}
<button class="{{ btn_class }}" disabled>{{ page }}</button>
{% else %}
<a href="?page={{ page }}" class="{{ btn_class }}">{{ page }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}" class="{{ btn_class }}">
下一頁<i class="fas fa-chevron-circle-right"></i>
</a>
{% endif %}
</div>
{% endwith %}
{% endif %}
接下來在報修項目列表的頁面範本中引入剛才建好的分頁控制項範本,這樣在列表的頁面上,若資料筆數超過指定數量,就會出現分頁控制的連結。
請修改 repair/log/templates/log/logitem_list.html
:
{% extends 'base.html' %}
{% block content %}
<table class="table table-sm table-hover">
<thead>
<tr>
<th>報修時間</th>
<th>報修主旨</th>
<th>報修人</th>
<th>狀態</th>
<th>最後更新時間</th>
</tr>
</thead>
<tbody>
{% for item in logitem_list %}
<tr>
<td>{{ item.ctime }}</td>
<td>
<a href="{{ item.id }}">{{ item.subject }}</a>
</td>
<td>{{ item.reporter }}</td>
<td>{{ item.get_status_display }}</td>
<td>{{ item.utime }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include 'pagination.html' %}
{% endblock %}
突顯報修記錄的狀態
報修記錄列表以及檢視報修記錄的頁面中,報修記錄的處理狀態是以純文字的方式呈現,如果要突顯處理狀態的話,可以考慮使用 Bootstrap 的徽章(Badge)來標示。
徽章(Badge)
要將網頁上的元件以 Bootstrap 的徽章方式呈現的話,該元件需套用 badge badge-{type}
類別,其中 {type}
的種類共有 primary
、 secondary
、 success
、 danger
、 warning
、 info
、 light
以及 dark
等,各種類的徽章的外觀大致如下圖所示:
假設要讓「待處理」、「處理中」、「已處理」等 3 種處理狀態分別套用 badge-danger
、 badge-warning
以及 badge-success
的話,可以將 repair/log/templates/log/logitem_list.html
的第 22 行由原本的:
<td>{{ item.get_status_display }}</td>
修改為
<td>
{% if item.status == 0 %}
<span class="badge badge-danger">
{% elif item.status == 1 %}
<span class="badge badge-warning">
{% else %}
<span class="badge badge-success">
{% endif %}
{{ item.get_status_display }}
</span>
</td>
統一指定處理狀態要套用的 CSS 類別
既然要套用的類別與 item.status
有對應關係,這邊提供另一種做法,乾脆直接在 LogItem
這個 model 中定義一個一個成員函式,可以根據 status
的值傳回對應的 CSS 類別字串。
修改資料模型的定義檔 repair/log/models.py
:
from django.db import models
class LogItem(models.Model):
ST_OPTIONS = [
(0, '待處理'),
(1, '處理中'),
(2, '已結案'),
]
subject = models.CharField('報修主旨', max_length=255)
description = models.TextField('報修內容')
reporter = models.CharField('報修人', max_length=30)
phone = models.CharField('聯絡電話', max_length=30)
ctime = models.DateTimeField('報修時間', auto_now_add=True)
handler = models.CharField('處理人員', max_length=30)
status = models.IntegerField(
'處理進度',
default=0,
choices=ST_OPTIONS
)
comment = models.TextField('處理說明')
utime = models.DateTimeField('最後更新時間', auto_now=True)
def __str__(self):
return self.subject
def get_status_class(self):
return ['danger', 'warning', 'success'][self.status]
接著修改報修項目列表頁面範本 repair/log/templates/log/logitem_list.html
:
{% extends 'base.html' %}
{% block content %}
<table class="table table-sm table-hover">
<thead>
<tr>
<th>報修時間</th>
<th>報修主旨</th>
<th>報修人</th>
<th>狀態</th>
<th>最後更新時間</th>
</tr>
</thead>
<tbody>
{% for item in logitem_list %}
<tr>
<td>{{ item.ctime }}</td>
<td>
<a href="{{ item.id }}">{{ item.subject }}</a>
</td>
<td>{{ item.reporter }}</td>
<td>
<span class="badge badge-{{ item.get_status_class }}">
{{ item.get_status_display }}
</span>
</td>
<td>{{ item.utime }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include 'pagination.html' %}
{% endblock %}
套用相同方式對 repair/log/templates/log/logitem_detail.html
進行修改:
{% extends 'base.html' %}
{% block content %}
<div class="card">
<div class="card-header">
<div class="h3">{{ logitem.subject }}</div>
</div>
<div class="card-body">
<div class="card-text">
{{ logitem.description|linebreaks }}
</div>
</div>
<div class="card-footer card-text d-flex justify-content-between text-muted">
<small title="報修人"><i class="fas fa-user"></i> {{ logitem.reporter }} <i class="fas fa-phone"></i> {{ logitem.phone }}</small>
<small><i class="far fa-clock"></i> {{ logitem.ctime }}</small>
</div>
</div>
<hr>
<div class="card mt-3">
<div class="card-header d-flex justify-content-between">
<div class="h3">處理狀況說明</div>
<div>
<span class="badge badge-{{ logitem.get_status_class }}">
{{ logitem.get_status_display }}
</span>
</div>
</div>
<div class="card-body">{{ logitem.comment|linebreaks }}</div>
<div class="card-footer card-text d-flex justify-content-between text-muted">
<small title="處理人員"><i class="fas fa-user-md"></i> {{ logitem.handler }}</small>
<small><i class="far fa-clock"></i> {{ logitem.utime }}</small>
</div>
</div>
{% endblock %}
建立資料庫與表單
修改
repair/log/models.py
:另外,在第一次進行資料庫遷移時,記得以專案管理腳本的
createsuperuser
參數來建立管理員帳號:接下來就可以將專案網站服務執行起來,以便在開發過程中進行測試:
決定好路徑與功能的對應關係之後,先修改專案的路徑規則檔
repair/repair/urls.py
:接著就將焦點放在應用程式
log
上,先來定義它自己的路徑規則。請新增檔案repair/log/urls.py
:定義處理視圖
接著來撰寫每條路徑規則相對應的處理視圖,請開啟
repair/log/views.py
,修改為以下程式碼:頁面範本
網站基底頁面範本
建立放置頁面範本的資料夾
repair/log/templates
以及repair/log/templates/log
。為了維持專案網站外觀的一致性,先新增網站基底範本
repair/log/templates/base.html
,並引入 Bootstrap CSS 框架與 FontAwesome 框架:新增導覽列範本檔
repair/log/templates/navbar.html
:報修記錄列表
建立報修記錄列表範本檔
repair/log/templates/log/logitem_list.html
:新增報修記錄
建立新增報修記錄範本檔
repair/log/templates/log/logitem_form.html
:檢視報修記錄
新增檔案
repair/log/temapltes/web/logitem_detail.html
分頁顯示
在報修項目列表的頁面中,當系統上線時間一長,累積的報修事項過多時,一般都會採用分頁顯示的方式來顯示列表,避免在列表頁面上顯示過多資料。
開啟
repair/log/views.py
,修改LogList
:新增分頁控制項範本
repair/log/templates/pagination.html
:接下來在報修項目列表的頁面範本中引入剛才建好的分頁控制項範本,這樣在列表的頁面上,若資料筆數超過指定數量,就會出現分頁控制的連結。
請修改
repair/log/templates/log/logitem_list.html
:突顯報修記錄的狀態
報修記錄列表以及檢視報修記錄的頁面中,報修記錄的處理狀態是以純文字的方式呈現,如果要突顯處理狀態的話,可以考慮使用 Bootstrap 的徽章(Badge)來標示。
徽章(Badge)
要將網頁上的元件以 Bootstrap 的徽章方式呈現的話,該元件需套用
badge badge-{type}
類別,其中{type}
的種類共有primary
、secondary
、success
、danger
、warning
、info
、light
以及dark
等,各種類的徽章的外觀大致如下圖所示:假設要讓「待處理」、「處理中」、「已處理」等 3 種處理狀態分別套用
badge-danger
、badge-warning
以及badge-success
的話,可以將repair/log/templates/log/logitem_list.html
的第 22 行由原本的:修改為
統一指定處理狀態要套用的 CSS 類別
既然要套用的類別與
item.status
有對應關係,這邊提供另一種做法,乾脆直接在LogItem
這個 model 中定義一個一個成員函式,可以根據status
的值傳回對應的 CSS 類別字串。修改資料模型的定義檔
repair/log/models.py
:接著修改報修項目列表頁面範本
repair/log/templates/log/logitem_list.html
:套用相同方式對
repair/log/templates/log/logitem_detail.html
進行修改: