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