Django -- 從平凡到超凡

第 10 章    範本繼承

(1) 三振就重構

▸ 不曉得您是否注意到,目前其實有個超級三振,但是還沒出局,那就是各個範本裡有許多資料都是相同的,如下:

<!doctype html>
{% load staticfiles %}
<html>
  <head>
    <title>部落格</title>
    <meta charset="utf-8">
    ...
  </head>
  <body>
    ...
  </body>
</html>

--> 嚴重違反 DRY 原則

▸ 解決方案:利用 Django 的範本繼承 (Template inheritance),消除重複部份

▸ 步驟:

1. 確認每個範本裡重複出現的部份
2. 將這些重複出現的資料放在基礎範本 (Base template) 裡,然後定義一些區塊標籤 (Block tag) ,讓其他範本可以置換區塊的內容
3. 其他的範本繼承基礎範本,並各自設定區塊的內容

(2) 重複出現的 HTML 碼與基礎範本

∗ 範本區塊標籤 (Template block tag)

▸ 分析目前各個範本可以發現以下藍色部份都重複出現,紅色部份則各個範本不同

<!doctype html>
{% load staticfiles %}
<html>
  <head>
    <title>部落格</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="{% static 'main/css/main.css' %}">
    
    <!-- 各範本連結 CSS 不同 -->
    
  </head>
  <body>
  
    <!-- 各範本內容不同 -->
  
    <!-- 各範本連結 script 不同 -->
    
  </body>
</html>

▸ 這些相同部份應該利用「繼承」(Inheriant) 而來,不要每個範本都撰寫

▸ 建立一個基礎範本 main/templates/main/base.html ,其內容如下:

<!doctype html>
{% load staticfiles %}
<html>
  <head>
    <title>部落格</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="{% static 'main/css/main.css' %}">
    {% block css %}{% endblock %}
  </head>
  <body>
    {% include 'main/menu.html' %}
    <h2>部落格 -- {% block heading %}{% endblock %}</h2>
    {% include 'main/messages.html' %}
    {% block content %}{% endblock %}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    {% block script %}{% endblock %}
  </body>
</html>
✶ 範本區塊標籤指定一個區塊,讓繼承的範本可以設定該區塊的內容,因此各個範本設定不同的內容,就會產生不同的頁面
✶ 區塊標籤格式:
{% block <blockName> %}...{% endblock %}
# {% block <blockName> %}:開始標籤, <blockName> 是區塊名稱, 以 base.html 而言有 4 個區塊:名稱分別為cssheadingcontent、與 script
# {% endblock %}:結束標籤
✶ 如果區塊有預設資料,可以放在開始與結束標籤之間,例如:
{% block content %}這是預設內容{% endblock %}

(3) 將所有範本都改為繼承 base.html 範本

- about.html

{% extends 'main/base.html' %}
{% block heading %}關於{% endblock %}
{% block content %}
<p>歡迎來到我的部落格,您可盡情瀏覽並留言。</p>
{% endblock %}
{% extends ... %}:繼承 base.html 範本
{% block heading ... %}:將 base.html 裡的 heading 區塊內容置換為 關於
{% block content ... %}:將 base.html 裡的 content 區塊內容置換為 <p>歡迎來到我的部落格,您可盡情瀏覽並留言。</p>
--> 測試:localhost:8000/main/about/
inheritanceAbout

- main.html

{% extends 'main/base.html' %}
{% block heading %}首頁{% endblock %}
{% block content %}
<p>{{ like }}</p>
{% endblock %}
--> 測試:localhost:8000/main/
inheritanceMain

- article.html

{% extends 'main/base.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'article/css/article.css' %}">
{% endblock %}
{% block heading %}歡迎蒞臨{% endblock %}
{% block content %}
{% include 'article/searchForm.html' %}
<p class="inlineBlock"><a class="btn" href="{% url 'article:articleCreate' %}">新增文章</a></p>

  ...

  {% endfor %}
  <hr>
{% endfor %}
{% endblock %}
{% block script %}
  <script src={% static 'main/js/deleteConfirm.js' %}></script>
{% endblock %}
✶ 注意:各個範本中若有靜態檔案,仍需分別加入 {% load staticfiles % }
--> 測試
inheritanceArticle

- articleCreateUpdate.html

{% extends 'main/base.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'article/css/article.css' %}">
{% endblock %}
{% block heading %}
  {% if articleForm.instance.id %}
    修改文章
  {% else %}
    新增文章
  {% endif %}
{% endblock %}
{% block content %}
{% if articleForm.instance.id %}
  <h1> 修改文章</h1> 
  <form method="post" action="{% url 'article:articleUpdate' articleForm.instance.id %}"> 
{% else %}
  <h1>新增文章</h1> 
  <form method="post" action="{% url 'article:articleCreate' %}"> 
{% endif %}

    ...

  </form> 
{% endblock %}
--> 測試
inheritanceCreate

- articleRead.html

{% extends 'main/base.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'article/css/article.css' %}">
{% endblock %}
{% block heading %}閱讀文章{% endblock %}
{% block content %}
<h3 class="inlineBlock">{{ article.title }}</h3>

...

{% endfor %}
{% endblock %}
--> 測試
inheritanceRead

- articleSearch.html

{% extends 'main/base.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'article/css/article.css' %}">
{% endblock %}
{% block heading %}搜尋{% endblock %}
{% block content %}
{% include 'article/searchForm.html' %}

...

{% endif %}
{% endblock %}
--> 測試
inheritanceSearch

(4) 小結

∗ 上推專案到 Github

▸ Right click project --> Team --> Commit --> Commit message: Chapter 10 finished --> Commit and Push

∗ 練習

▸ 將 bookstore 專案中的各範本亦改為範本繼承

上一章       下一章