{"path":"51974","ref":"template_tags.md","title":"Template tags","content":"# Template tags\n\n在先前的 Templates 章節中,我們已經學會基礎的 Django Template 用法 (在 Template 裡呈現變數內容)。但為了產生完整的網頁,我們會需要能在 Template 裡執行一些簡單的 Python 語法,例如:\n\n- **邏輯判斷** (if else) -- 若使用者己經登入,則顯示使用者的暱稱;若未登入,則顯示登入按鈕\n- **重覆 HTML 片段** (for loop) -- 列出所有好友的ID 和顯示圖片\n- **格式化 Template 中的變數** -- 例如日期的格式化\n\n因為我們 [Django template tags](https:\/\/docs.djangoproject.com\/en\/1.7\/ref\/templates\/builtins\/) 讓你可以在 HTML 檔案裡使用類似 Python 的語法,動態存取 View 傳過來的變數,或是在顯示到瀏覽器之前幫你做簡單的資料判斷、轉換、計算等等。\n\n在這一章,我們將到使用 Django ORM 存取資料庫 ,撈出旅遊日記全部的 Post 傳入 Template。並使用 Django 的 Template Tag 、Template Filter 一步步產生旅遊日記的首頁。\n\n### 建立旅遊日記的首頁\n\n### 確認首頁需求\n\n在開始動工之前,我們先確認需求。\n\n旅遊日記的首頁應該會有:\n\n1. 標題\n1. 照片\n1. 發佈日期\n1. 部份的遊記內文\n\n### 建立首頁的 View\n\n首先,我們先建立一個新的 View function - `home()`:\n\n~~~\n# trips\/views.py\n\nfrom django.shortcuts import render\nfrom trips.models import Post\n\ndef home(request):\n # get all the posts\n post_list = Post.objects.all()\n return render(request,\n 'home.html',\n {'post_list': post_list})\n~~~\n\n- **匯入所需的 Model** -- 記得 import 需要用到的 Model `Post`\n- **取得所有Post** -- 透過`Post.objects.all()`,從資料庫取得全部的 post ,並回傳至 `home.html` 這個 template。\n\n### 設定首頁的 Url\n\n接下來,我們修改 **urls.py** ,將首頁 ( 正規表達式`^$` ) 指向 **home()** 這個 View function:\n\n~~~\n# mysite\/urls.py\nfrom trips.views import hello_world, home\n\nurlpatterns = patterns('',\n ...\n url(r'^$', home),\n)\n~~~\n\n### Template tags\n\n### 建立首頁的 Template 並印出 post_list\n\n首先,在 templates 資料夾底下新增 `home.html`:\n\n~~~\n\n\n{{ post_list }}\n~~~\n\n打開瀏覽器進入首頁 [http:\/\/127.0.0.1:8000\/](http:\/\/127.0.0.1:8000\/),可以看到 *post_list* 已呈現至網頁上了。\n\n![Plain post_list in Template](https:\/\/box.kancloud.cn\/2015-08-18_55d2cc1a5e569.png)\n\n### 顯示 Post中的資料\n\n仔細觀察印出的 *post_list*,會發現是以 List 的形式顯示。但我們希望的則是:**存取這個 Post List 中每個元素的資料,並印出來**。\n\n為了達成這個功能,我們會用到 `for` 這個 Template tag。\n\n#### for loop\n\n在寫 Python 時,若想存取 List 裡的每一個元素,我們會使用 `for` 迴圈。而在 Django Template 中,也提供了類似的 template tags -- [{% for %}](https:\/\/docs.djangoproject.com\/en\/1.7\/ref\/templates\/builtins\/#for)。\n\n**for**\n\n在 Template 中使用類似 Python 的 for 迴圈,使用方法如下:\n\n~~~\n{% for in %}\n ...\n{% endfor %}\n~~~\n\n瞭解了 **for** 的用法後,我們試著印出首頁所需的資訊。修改`home.html`如下:\n\n~~~\n\n\n{% for post in post_list %}\n
\n {{ post.title }}\n {{ post.created_at }}\n {{ post.photo }}\n {{ post.content }}\n <\/div>\n{% endfor %}\n~~~\n\n- 開始標籤為 `{% for %}` 開始;結束標籤為 `{% endfor %}`\n- *post_list* 中有 3 個元素,所以 for 區塊中的內容會執行 3 次\n- 迴圈中,使用標籤`{{ var }}`,反覆印出每個 post 中的標題、建立時間、照片網址和文章內容\n\n重新整理瀏覽器,網頁上會有首頁所需的 post 資訊:\n\n![](https:\/\/box.kancloud.cn\/2015-08-18_55d2cc1a72e89.png)\n\n### 顯示照片\n\n現在網頁已經有照片網址,我們稍微修改 Template ,讓照片以圖片方式呈現\n\n~~~\n
\n \"\"\n<\/div>\n~~~\n\n### 處理沒有照片的遊記\n\n#### if...else\n\n另一個常用的 template tags 是 [if](https:\/\/docs.djangoproject.com\/en\/1.7\/ref\/templates\/builtins\/#if) 判斷式,用法如下:\n\n~~~\n{% if post.photo %}\n
\n \"\"\n <\/div>\n{% else %}\n
<\/div>\n{% endif %}\n~~~\n\n- 符合條件所想要顯示的 HTML 放在 `{% if`*``*`%}` 區塊裡\n- 不符合的則放在`{% else %}`區塊裡面\n- 最後跟 **for** 一樣,要加上`{% endif %}`作為判斷式結尾。\n\n在這裡,我們判斷如果 *post.photo* 有值就顯示照片,沒有就多加上一個 CSS class `photo-default`另外處理。\n\n### Template filter\n\n除了 template tags ,Django 也內建也許多好用的 [template filter](https:\/\/docs.djangoproject.com\/en\/1.7\/ref\/templates\/builtins\/#built-in-filter-reference)。它能在變數顯示之前幫你做計算、設定預設值,置中、或是截斷過長的內容......等等。使用方法如下:\n\n`{{`*``*`|`*``*`:`*``*`}}`\n\n- **< variable_name > ** -- 變數名稱\n- **< filter_name > ** -- filter 名稱,例如`add`, `cut`等等\n- **< filter_arguments > ** -- 要傳入 filter 的參數\n\n#### 變更時間的顯示格式\n\n在這裡,我們只練習一種很常用的 filter - **[date](https:\/\/docs.djangoproject.com\/en\/1.7\/ref\/templates\/builtins\/#date)**。它可以將`datetime`型別的物件,以指定的時間格式 Date Format ( 例如:`Y \/ m \/ d` )輸出。\n\n我們試著將 `created_at` 時間,以 `年 \/ 月 \/ 日` 的形式顯示:\n\n~~~\n{{ post.created_at|date:\"Y \/ m \/ d\" }}\n~~~\n\n### 完整的 HTML 與 CSS\n\n接著,補上完整的 HTML 標籤,並加上 CSS 樣式後,旅遊日記首頁就完成了。\n\n### 最終版 *home.html* 程式碼如下:\n\n~~~\n\n\n\n\n\n \n A Django Girl's Adventure<\/title>\n <link href=\"\/\/fonts.googleapis.com\/css?family=Lemon\" rel=\"stylesheet\" type=\"text\/css\">\n <link href=\"\/\/maxcdn.bootstrapcdn.com\/font-awesome\/4.2.0\/css\/font-awesome.min.css\" rel=\"stylesheet\" type=\"text\/css\">\n <link href=\"\/\/djangogirlstaipei.github.io\/assets\/css\/style.css\" rel=\"stylesheet\" type=\"text\/css\">\n<\/head>\n<body>\n <div class=\"header\">\n <h1 class=\"site-title text-center\">\n <a href=\"\/\">A Django Girl's Adventure<\/a>\n <\/h1>\n <\/div>\n <div class=\"container\">\n {% for post in post_list %}\n <div class=\"post-wrapper\">\n <div class=\"post\">\n <div class=\"post-heading\">\n <h2 class=\"title\">\n <a href=\"#\">{{ post.title }}<\/a>\n <\/h2>\n <div class=\"date\">{{ post.created_at|date:\"Y \/ m \/ d\" }}<\/div>\n <\/div>\n {% if post.photo %}\n <div class=\"thumbnail\">\n <img src=\"{{ post.photo }}\" alt=\"\">\n <\/div>\n {% else %}\n <div class=\"thumbnail thumbnail-default\"><\/div>\n {% endif %}\n <div class=\"post-content read-more-block\">\n {{ post.content }}\n <\/div>\n <div class=\"post-footer\">\n <a class=\"read-more\" href=\"#\">\n Read More <i class=\"fa fa-arrow-right\"><\/i>\n <\/a>\n <\/div>\n <\/div>\n <\/div>\n {% endfor %}\n <\/div>\n<\/body>\n<\/html>\n~~~\n\n打開 [http:\/\/127.0.0.1:8000\/](http:\/\/127.0.0.1:8000\/) 看一下你的成果吧!\n\n![Django Girls Trips - Home page](https:\/\/box.kancloud.cn\/2015-08-18_55d2cc1a84c07.png)\n\n### 小結\n\n最後,我們複習一下本章學到的 **Template Tag** 與 **Template Filter**:\n\n** Template Tag**\n\n| 語法 | 說明 | \n|-----|-----|\n| {% **for** ... **in** ... %}...{% **endfor** %} | 類似 Python 的 for 迴圈,反覆執行 for 區塊中的內容 | \n| {% **if** %} ... {% **else** %} ... {% **endif** %}` | 在 Template Tags 中進行 if/else 的邏輯判斷 | \n\n** Template Filter**\n\n| 語法 | 說明 | \n|-----|-----|\n| {{ value **|date:***`<date_format>`* }} | 可以將`datetime`型別的物件,以指定的時間格式 Date Format 輸出 |"}