發起討論主題

本專案內有兩種類型的資料:討論主題以及針對某主題的回覆。

定義討論主題資料表

修改 forum/topic/models.py,內容如下:

from django.db import models from django.contrib.auth.models import User # Create your models here. # 討論主題 class Topic(models.Model): subject = models.CharField('討論主題', max_length=255) content = models.TextField('內文') author = models.ForeignKey(User, on_delete=models.CASCADE) created = models.DateTimeField('建立時間', auto_now_add=True) replied = models.DateTimeField('回覆時間', null=True, blank=True) def __str__(self): return "{}: {}".format(self.author, self.subject)
    ```

執行以下指令將資料模型的變更套用到資料庫,並建立一個管理員的帳號:

python manage.py makemigrations python manage.py migrate python manage.py createsuperuser

開啟網站服務

python manage.py runserver 0.0.0.0:80

定義網站存取路徑規則

新增第 18, 22, 23 行

from django.contrib import admin from django.urls import path, include from django.views.generic import RedirectView urlpatterns = [ path('admin/', admin.site.urls), path('topic/', include('topic.urls')), path('', RedirectView.as_view(url='topic/')), ]

接著,為應用程式 topic 新增路徑規則。請新增檔案 forum/topic/urls.py,內容如下:

from django.urls import path from .views import * urlpatterns = [ path('', TopicList.as_view(), name='topic_list'), path('new/', TopicNew.as_view(), name='topic_new'), path('<int:pk>/', TopicView.as_view(), name='topic_view'), ]

定義處理視圖

接著來撰寫每條路徑規則相對應的處理視圖,請開啟 forum/topic/views.py ,修改為以下程式碼:

from django.views.generic import * from django.urls import reverse from .models import * # 討論主題列表 class TopicList(ListView): model = Topic ordering = ['-created'] paginate_by = 20 # 每頁主題數 # 新增討論主題 class TopicNew(CreateView): model = Topic fields = ['subject', 'content'] def get_success_url(self): return reverse('topic_list') def form_valid(self, form): # 自動將目前使用者填入討論主題的作者欄 form.instance.author = self.request.user return super().form_valid(form) # 檢視討論主題 class TopicView(DetailView): model = Topic

頁面範本

先前在建立專案時,已修改過專案設定檔 forum/forum/settings.py,指定了要將頁面範本放在專案的 pagetmpl 資料夾中,記得在撰寫頁面範本之前,要先在專案資料夾中建立 pagetmpl 資料夾。

網站基底範本

新增網站基底範本檔案 forum/pagetmpl/base.html,同樣引用了 BootstrapFont Awesome 兩個框架來調整網站的外觀:

<!doctype html> <html lang="zh-hant"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <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> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <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>

導覽列

新增導覽列範本 forum/pagetmpl/navbar.html

<!-- Navbar begin //--> <nav class="navbar navbar-expand-sm navbar-dark bg-primary mb-2"> <!-- 網站標誌 --> <div class="navbar-brand"> <i class="far fa-comment-alt"></i> 討論區 </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"> <li class="nav-item"> <a href="{% url 'topic_list' %}" class="nav-link"> <i class="fas fa-list"></i> 所有主題 </a> </li> <li class="nav-item"> <a href="{% url 'topic_new' %}" class="nav-link"> <i class="fas fa-edit"></i> 發起討論 </a> </li> </ul> </div> </nav> <!-- Navbar end //-->

討論主題列表

先新增資料夾 forum/pagetmpl/topic,然後新增討論主題列表範本檔案 forum/pagetmpl/topic/topic_list.html

{% extends "base.html" %} {% block content %} <table class="table table-sm"> <thead> <tr class="text-light bg-dark"> <th>發起時間</th> <th>討論主題</th> <th>發起人</th> <th>回覆時間</th> </tr> </thead> <tbody> {% for topic in topic_list %} <tr> <td>{{topic.created|date:"Y/m/d H:i"}}</td> <td> <a href="{% url 'topic_view' topic.id %}">{{ topic.subject }}</a> </td> <td>{{topic.author}}</td> <td>{{topic.replied|date:"Y/m/d H:i"}}</td> </tr> {% endfor %} </tbody> </table> {% include "pagination.html" %} {% endblock %}

分頁控制項同樣分開寫,如果需要的話,就可以直接引用。新增分會控制項的範本檔 forum/pagetmpl/pagination.html

{% if is_paginated %} {% with btn_class="btn btn-sm btn-secondary" %} <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 %}

檢視討論主題

新增討論主題檢視範本檔案 forum/pagetmpl/topic/topic_detail.html

{% extends "base.html" %} {% block content %} <div class="card"> <div class="card-header d-md-flex justify-content-between"> <div class="h3">{{ topic.subject }}</div> <div class="text-muted"> <small><i class="fas fa-user"></i> {{ topic.author }}</small> <small><i class="fas fa-clock"></i> {{ topic.created|date:"Y/m/d H:i" }}</small> </div> </div> <div class="card-body"> {{ topic.content|linebreaks }} </div> </div> {% endblock %}

新增討論主題

新增表單範本檔案 forum/pagetmpl/topic/topic_form.html

{% extends "base.html" %} {% block content %} <form action="" method="post"> {% csrf_token %} <table class="table table-sm"> {{ form.as_table }} </table> <input type="submit" class="btn btn-primary" value="送出"> </form> <script> var inputs = document.querySelectorAll('table input, table textarea, table select'); inputs.forEach(function(item) { item.classList.add('form-control'); }); </script> {% endblock %}