Flask四之模板

netScorpion發表於2019-02-16

四、模板

FMTV
F:form表單
M:Model模型(資料庫)
T:Template模板
V:view檢視(路由)

1、渲染模板

模板是一個包含響應文字的檔案,其中包含用佔位變數表示的動態部分,其具體值
只在請求的上下文中才能知道。 使用真實值替換變數,再返回最終得到的響應字元
串,這一過程稱為渲染。可以使用 render_template() 方法來渲染模板。你需要做
的一切就是將模板名和你想作為關鍵字的引數傳入模板的變數。
Flask 會在 templates 資料夾裡尋找模板。所以,如果你的應用是個模組,這個文
件夾應該與模組同級;如果它是一個包,那麼這個資料夾作為包的子目錄:
模板:
/application.py
/templates
    /hello.html

包:

/application
    /__init__.py
    /templates
        /hello.html

【hello.html】

<h1>Hello World!</h1>


from flask import render_template
@app.route(`/hellotemplate/`)
def hellotemplate():
    return render_template(`hello.html`)

模板引擎
Flask使用了一個名為 Jinja2 的強大模板引擎

  • {% … %} Jinja語句,例如判斷、迴圈語句

  • {{ … }} 變數,會顯示在瀏覽器中

  • {# … #} 註釋,不會輸出到瀏覽器中

2、變數規則

在模板中使用的 {{ name }} 結構表示一個變數,它是一種特殊的佔位符,告訴
模板引擎這個位置的值從渲染模板時使用的資料中獲取。
【helloname.html】

<h1>Hello, {{ name }}!</h1>

@app.route(`/hellotemplate/<name>`)
def helloname(name):
    return render_template(`helloname.html`,name = name)

可以使用過濾器修改變數,過濾器名新增在變數名之後,中間使用豎線分隔。

3、控制結構

1、條件控制語句
【if.html】

{% if name %}
hello, {{name}}
{% else %}
hello, world!
{% endif %}

2、 for 迴圈
【for.html】

<ol>
    {% for a in range(10) %}
    <li>a</li>
    {% endfor %}
</ol>

@app.route(`/for/`)
def fortemplate():
    return render_template(`for.html`)

3、Jinja2 還支援巨集(macro) 。巨集類似於 Python 程式碼中的函式(def)。
【macro.html】

{% macro myprint(A) %}
this is {{ A }}
{% endmacro %}

{{ myprint(A) }}


@app.route(`/macro/<a>`)
def macrotamplate(a):
    return render_template(`macro.html`,A = a)

為了重複使用巨集,我們可以將其儲存在單獨的檔案中,然後在需要使用的模板中匯入:
【macro2.html】

{% from `macro.html` import myprint %}
{{ myprint(A) }}

@app.route(`/macro2/<a>`)
def macro2template(a):
    return render_template(`macro2.html`,A = a)

4、包含(include)
【include.html】

{% include `macro.html` %}


@app.route(`/include/<a>`)
def includetemplate(a):
    return render_template(`include.html`,A = a)

【注意】
包含進來的檔案裡的所有變數也包含進來了,需要在檢視函式中指定

4、模板繼承

首先,建立一個名為 base.html 的基模板:
【base.html】

<html>
<head>
    {% block head %}
    <title>
        {% block title %}
        {% endblock %}
        - My Application
    </title>
    {% endblock %}
</head>

<body>
{% block body %}
{% endblock %}
</body>

</html>

block 標籤定義的元素可在衍生模板中修改。下面這個示例是基模板的衍生模板:
【extend.html】

% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<h1>super</h1>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
extends 指令宣告這個模板衍生自 base.html。在 extends 指令之後,基模板中的
3個塊被重新定義,模板引擎會將其插入適當的位置。如果想新增內容到在父模板
內已經定義的塊,又不想失去父模板裡的內容,可以使用super函式

5、使用Flask-Bootstrap

Flask-Bootstrap 使用 pip安裝:

(venv) $ pip install flask-bootstrap

Flask 擴充套件一般都在建立程式例項後就初始化。
初始化 Flask-Bootstrap 之後,就可以在程式中使用一個包含所有 Bootstrap 檔案
的基模板。
【boootstrap.html】

{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle"
                    data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class="container">
    <div class="page-header">
        <h1>Hello, {{ name }}!</h1>
    </div>
</div>
{% endblock %}
Jinja2 中的 extends 指令從 Flask-Bootstrap 中匯入 bootstrap/base.html,從而
實現模板繼承。

Flask-Bootstrap 中的基模板提供了一個網頁框架,引入了 Bootstrap 中的所有 CSS 
和JavaScript 檔案。基模板中定義了可在衍生模板中重定義的塊。 block 和 endblock 
指令定義的塊中的內容可新增到基模板中。
上面這個 boootstrap.html 模板定義了 3 個塊,分別名為 title、 navbar 和 content。
這些塊都是基模板提供的, 可在衍生模板中重新定義。 title 塊的作用很明顯,其中
的內容會出現在渲染後的 HTML 文件頭部,放在 <title> 標籤中。 navbar 和 content 
這兩個塊分別表示頁面中的導航條和主體內容。在這個模板中, navbar 塊使用 Bootstrap 
元件定義了一個簡單的導航條。content 塊中有個<div> 容器,其中包含一個頁面頭部。
之前版本的模板中的歡迎資訊,現在就放在這個頁面頭部。
from flask_bootstrap import Bootstrap
bootstrap = Bootstrap(app)
@app.route(`/bootstrap/<name>`)
def bootstraptemplate(name):
    return render_template(`boootstrap.html`,name = name)

【注意】
很多塊都是 Flask-Bootstrap 自用的,如果直接重定義可能會導致一些問題。例如,
Bootstrap 所需的檔案在 styles 和 scripts 塊中宣告。如果程式需要向已經有內
容的塊中新增新內容,必須使用Jinja2 提供的 super() 函式。例如,如果要在衍生
模板中新增新的 JavaScript 檔案,需要這麼定義 scripts 塊:

{% block scripts %}
{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}

6、自定義錯誤頁面

【templates/404.html】

<h1> Page is not Found </h1>
@app.errorhandler(404)
def page_not_found(e):
    return render_template(`404.html`), 404

【templates/base.html: 包含導航條的程式基模板】

{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for(`static`, filename=`favicon.ico`) }}" type="image/x -icon">
<link rel="icon" href="{{ url_for(`static`, filename=`favicon.ico`) }}" type="image/x -icon">
{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}

{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}

這個模板的 content 塊中只有一個 <div> 容器,其中包含了一個名為
page_content 的新的空塊,塊中的內容由衍生模板定義。

【templates/404.html:使用模板繼承機制自定義 404 錯誤頁面】

{% extends "base.html" %}
{% block title %}Flasky - Page Not Found{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Not Found</h1>
</div>
{% endblock %}

templates/boootstrap.html 現在可以通過繼承這個基模板來簡化內容:
【 templates/boootstrap.html: 使用模板繼承機制簡化頁面模板】

{% extends "base.html" %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
{% endblock %}

7、靜態檔案

預設設定下, Flask 在程式根目錄中名為 static 的子目錄中尋找靜態檔案。
如果需要,可在static 資料夾中使用子資料夾存放檔案。給靜態檔案生成
URL ,使用特殊的 `static` 端點名:
【westeros.html】

<img src = "{{url_for(`static`,filename = `westeros.jpg`)}}">
@app.route(`/westeros/`)
def westeros():
    return render_template(`westeros.html`)

這個檔案應該儲存在檔案系統上的 static/westeros.jpg 。

8、使用Flask-Moment本地化日期和時間

lask-Moment 是一個 Flask 程式擴充套件,能把moment.js 整合到 Jinja2 模
板中。 Flask-Moment 可以使用 pip 安裝:

(venv) $ pip install flask-moment

這個擴充套件的初始化方法和Bootstrap一樣,以程式例項app為引數:

from flask_moment import Moment
moment = Moment(app)

除了 moment.js, Flask-Moment 還依賴 jquery.js。要在 HTML 文件的某個
地方引入這兩個庫,可以直接引入,這樣可以選擇使用哪個版本,也可使用擴
展提供的輔助函式,從內容分發網路(Content Delivery Network, CDN)中
引入通過測試的版本。 Bootstrap 已經引入了 jquery.js, 因此只需引入
moment.js即可。
【base.html中增加了】

{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}

【moment.html】

{% extends "base.html" %}
{% block page_content %}
<div class="page-header">
<h1>Hello World!</h1>
</div>
<p>The local date and time is {{moment(current_time).format(`LLL`)}}.</p>
<p>That was {{moment(current_time).fromNow(refresh = true)}}.</p>
{% endblock %}

把變數current_time 傳入模板進行渲染

from datetime import datetime
@app.route(`/moment/`)
def momenttemplate():
return render_template(`moment.html`,current_time = datetime.utcnow())

相關文章