1. 程式人生 > 實用技巧 >03.flask模板

03.flask模板

模板概述

一. 為什麼要使用模板

檢視函式有兩個作用, 一個是業務邏輯一個是表現邏輯, 舉例說明:

使用者在網站註冊了一個新賬號, 使用者在表單中輸入電子郵件地址和密碼, 點選提交按鈕, 伺服器接收到包含使用者輸入的請求, 然後Flask把請求分發到處理註冊請求的檢視函式。 這個檢視函式需要訪問資料庫, 新增新使用者(業務邏輯), 然後生成相應回送瀏覽器(表現邏輯)。

兩個完全獨立的作用被混淆到一起會使程式碼難以理解和維護, 所以我們選擇把表現邏輯(響應)遷移到模板當中去。

模板是包含響應文字的檔案,其中包含用佔位變量表示的動態部分,其具體值只在請求的上下文中才能知道。使用真實值替換變數,再返回最終得到的響應字串,這一過程稱為渲染。為了渲染模板,Flask 使用一個名為 Jinja2 的強大模板引擎。

二. 如何使用模板

  1. 如何渲染模板:
    • 模板放在templates資料夾下
    • flask中匯入render_template函式。
    • 在檢視函式中,使用render_template函式,渲染模板。注意:只需要填寫模板的名字,不需要填寫templates這個資料夾的路徑。
  2. 模板傳參:
    • 如果只有一個或者少量引數,直接在render_template函式中新增關鍵字引數就可以了。
    • 如果有多個引數的時候,那麼可以先把所有的引數放在字典中,然後在render_template中,
      使用兩個星號,把字典轉換成關鍵引數傳遞進去,這樣的程式碼更方便管理和使用。
  3. 在模板中,如果要使用一個變數,語法是:{{params}}
  4. 訪問模型中的物件屬性或者是字典,可以通過{{params.property}}的形式,或者是使用{{params['age']}}.

示例程式碼

template01 .py

#encoding: utf-8
from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')
def index():
    # 類
    class Person(object):
        name = u'p17bdw'
        age = 18

    p = Person()

    context = {
        'username': u'c17bdw',
        'gender': u'男',
        'age': 17,
        'person': p,    # 宣告
        'websites': {
            'baidu': 'www.baidu.com',
            'google': 'www.google.com'
        }
    }
    return render_template('anthoer/index.html',**context)

if __name__ == '__main__':
    app.run(debug=True)

anthoer/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    這是HTML檔案中出現的文字
    <p>使用者名稱:{{ username }}</p>
    <p>性別:{{ gender }}</p>
    <p>年齡:{{ age }}</p>

    <hr>
    <p>名字:{{ person['name'] }}</p>
    <p>年齡:{{ person.age }}</p>

    <hr>
    <p>百度:{{ websites['baidu'] }}</p>
    <p>谷歌:{{ websites['google'] }}</p>
</body>
</html>

if判斷

  1. 語法:
    {% if xxx %} {% else %} {% endif %}

  2. if的使用,可以和python中相差無幾。

示例程式碼

if_statement .py

# 輸入 http://127.0.0.1:5000/1/ 為登入狀態,否則為未登入狀態。

#encoding: utf-8

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/<is_login>/')
def index(is_login):
    if is_login == '1':
        user = {
            'username': u'17bdw',
            'age':20
        }
        return render_template('index.html',user=user)
    else:
        return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% if user and user.age > 18 %}
        <a href="#">{{ user.username }}</a>
        <a href="#">登出</a>
    {% else %}
        <a href="#">登入</a>
        <a href="#">註冊</a>
    {% endif %}
</body>
</html>

for迴圈遍歷列表和字典

1.  字典的遍歷,語法和`python`一樣,可以使用`items()`、`keys()`、`values()`、`iteritems()`、`iterkeys()`、`itervalues()`
    `{% for k,v in user.items() %} <p>{{ k }}:{{ v }}</p> {% endfor %}`
2.  列表的遍歷:語法和`python`一樣。
    `{% for website in websites %} <p>{{ website }}</p> {% endfor %}`

示例程式碼

for_statement .py

#encoding: utf-8

from flask import Flask,render_template

app = Flask(__name__)

# for遍歷字典

@app.route('/')
def index():
    books = [
        {
            'name': u'西遊記',
            'author': u'吳承恩',
            'price': 109
        },
        {
            'name': u'紅樓夢',
            'author': u'曹雪芹',
            'price': 200
        },
        {
            'name': u'三國演義',
            'author': u'羅貫中',
            'price': 120
        },
        {
            'name': u'水滸傳',
            'author': u'施耐庵',
            'price': 130
        }
    ]
    return render_template('index.html',books=books)

if __name__ == '__main__':
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<table>
    <thead>
        <th>書名</th>
        <th>作者</th>
        <th>價格</th>
    </thead>
    <tbody>
        {% for book in books %}
            <tr>
                <td>{{ book.name }}</td>
                <td>{{ book.author }}</td>
                <td>{{ book.price }}</td>
            </tr>
        {% endfor %}
    </tbody>
</table>

</body>
</html>

過濾器

  1. 介紹和語法:

    • 介紹:過濾器可以處理變數,把原始的變數經過處理後再展示出來。作用的物件是變數。
    • 語法:
      {{ avatar|default('xxx') }}
  2. default過濾器:如果當前變數不存在,這時候可以指定預設值。

  3. length過濾器:求列表或者字串或者字典或者元組的長度。

  4. 常用的過濾器:
    abs(value):返回一個數值的絕對值。示例:-1|abs
    default(value,default_value,boolean=false):如果當前變數沒有值,則會使用引數中的值來代替。示例:name|default('xiaotuo')——如果name不存在,則會使用xiaotuo來替代。boolean=False預設是在只有這個變數為undefined的時候才會使用default中的值,如果想使用python的形式判斷是否為false,則可以傳遞boolean=true。也可以使用or來替換。
    escape(value)或e:轉義字元,會將<、>等符號轉義成HTML中的符號。示例:content|escape或content|e。
    first(value):返回一個序列的第一個元素。示例:names|first
    last(value):返回一個序列的最後一個元素。示例:names|last。

    length(value):返回一個序列或者字典的長度。示例:names|length。
    join(value,d=u''):將一個序列用d這個引數的值拼接成字串。
    safe(value):如果開啟了全域性轉義,那麼safe過濾器會將變數關掉轉義。示例:content_html|safe。
    int(value):將值轉換為int型別。
    float(value):將值轉換為float型別。
    lower(value):將字串轉換為小寫。
    upper(value):將字串轉換為小寫。
    replace(value,old,new): 替換將old替換為new的字串。
    truncate(value,length=255,killwords=False):擷取length長度的字串。
    striptags(value):刪除字串中所有的HTML標籤,如果出現多個空格,將替換成一個空格。
    trim:擷取字串前面和後面的空白字元。
    string(value):將變數轉換成字串。
    wordcount(s):計算一個長字串中單詞的個數。

示例程式碼

filter_demo .py

#encoding: utf-8

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')
def index():
    comments = [
        {
            'user': u'admin',
            'content': 'xxxx'
        },
        {
            'user': u'tesr',
            'content': 'xxxx'
        }
    ]
    return render_template('index.html',comments=comments)

if __name__ == '__main__':
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>過濾器</title>
</head>
<body>

# 如果avatar這個變數不存在,就使用default過濾器提供的值

<img src="{{ avatar|default('http://avatar.csdn.net/1/D/B/3_hmzkekek41.jpg') }}" alt="">

<hr>

# length 計算長度
<p>評論數:({{ comments|length }})</p>
<ul>
    {% for comment in comments %}
        <li>
            <a href="#">{{ comment.user }}</a>
            <p>{{ comment.content }}</p>
        </li>
    {% endfor %}

</ul>
</body>
</html>

繼承和block

  1. 繼承作用和語法:

    • 作用:可以把一些公共的程式碼放在父模板中,避免每個模板寫同樣的程式碼。
    • 語法:

    {% extends 'base.html' %}

  2. block實現:

    • 作用:可以讓子模板實現一些自己的需求。父模板需要提前定義好。
    • 注意點:字模板中的程式碼,必須放在block塊中。

示例程式碼

app.py

#encoding: utf-8

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/login/')
def login():
    return render_template('login.html')

if __name__ == '__main__':
    app.run(debug=True)

index.html


{% extends 'base.html' %}

{% block head %}
    <style>

    </style>
    <link rel="stylesheet" href="">
    <script></script>
{% endblock %}

{% block title %}
    首頁
{% endblock %}

{% block main %}
    <h1>這是首頁</h1>
{% endblock %}

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
        <style>
        .nav{
            background: #3a3a3a;
            height: 65px;
        }
        ul{
            overflow: hidden;
        }
        ul li{
            float: left;
            list-style: none;
            padding: 0 10px;
            line-height: 65px;
        }
        ul li a{
            color: #fff;
        }
    </style>
    {% block head %}{% endblock %}
</head>
<body>
<div class="nav">
    <ul>
        <li><a href="/">首頁</a></li>
        <li><a href="/login">釋出問答</a></li>
    </ul>
</div>
{% block main %}{% endblock %}
</body>
</html>

login.html

{% extends 'base.html' %}

{% block title %}
    登入
{% endblock %}

{% block main %}
    <h1>這是登入頁面</h1>
{% endblock %}

使用Flask-Bootstrap整合Bootstrap

Bootstrap 是 Twitter 開發的一個開源 Web 框架,它提供的使用者介面元件可用於建立整潔且具有吸引力的網頁,而且相容所有現代的桌面和移動平臺 Web 瀏覽器。

要想在應用中整合 Bootstrap,最直接的方法是根據 Bootstrap 文件中的說明對 HTML 模板進行必要的改動。不過,這個任務使用 Flask擴充套件處理要簡單得多,而且相關的改動不會導致主邏輯凌亂不堪。

我們要使用的擴充套件是 Flask-Bootstrap,它可以使用 pip 安裝:

(venv) $ pip install flask-bootstrap

Flask 擴充套件在建立應用例項時初始化。

初始化 Flask-Bootstrap。

from flask_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)

@app.route('/user/<name>')
def user(name):
    return render_template('user.html', name=name)

擴充套件通常從flask_<name>包中匯入,其中<name>是擴充套件的名稱。多數 Flask 擴展采用兩種初始化方式中的一種。在示例中,初始化擴充套件的方式是把應用例項作為引數傳給建構函式。

初始化 Flask-Bootstrap 之後,就可以在應用中使用一個包含所有 Bootstrap 檔案和一般結構的基模板。應用利用 Jinja2 的模板繼承機制來擴充套件這個基模板。

templates/user.html:使用 Flask-Bootstrap 的模板

{% 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 檔案。

上面這個 user.html 模板定義了 3 個區塊,分別名為titlenavbarcontent。這些區塊都是基模板提供的,可在衍生模板中重新定義。title區塊的作用很明顯,其中的內容會出現在渲染後的 HTML 文件頭部,放在<title>標籤中。navbarcontent這兩個區塊分別表示頁面中的導航欄和主體內容。

在這個模板中,navbar區塊使用 Bootstrap 元件定義了一個簡單的導航欄。content區塊中有個<div>容器,其中包含一個頁頭。之前版本中的歡迎訊息,現在就放在這個頁頭裡。改動之後的應用如圖所示。

url連結

使用url_for(檢視函式名稱)可以反轉成url。

在模板中直接編寫簡單路由的 URL 連結不難,但對於包含可變部分的動態路由,在模板中構建正確的 URL 就很困難了。而且,直接編寫 URL 會對程式碼中定義的路由產生不必要的依賴關係。如果重新定義路由,模板中的連結可能會失效。

為了避免這些問題,Flask 提供了 url_for() 輔助函式,它使用應用的 URL 對映中儲存的資訊生成 URL。

url_for() 函式最簡單的用法是以檢視函式名作為引數,返回對應的 URL。例如,在當前版本的 app.py 應用中呼叫 url_for('index') 得到的結果是 /,即應用的根 URL。呼叫 url_for('index', _external=True) 返回的則是絕對地址,在這個示例中是 http://localhost:5000/。

使用 url_for() 生成動態 URL 時,將動態部分作為關鍵字引數傳入。例如,url_for('user', name='john', _external=True) 的返回結果是 http://localhost:5000/user/john。

傳給 url_for() 的關鍵字引數不僅限於動態路由中的引數,非動態的引數也會新增到查詢字串中。例如,url_for('user', name='john', page=2, version=1) 的返回結果是 /user/ john?page=2&version=1。

載入靜態檔案

Web 應用不是僅由 Python 程式碼和模板組成。多數應用還會使用靜態檔案,例如模板中 HTML 程式碼引用的影象、JavaScript 原始碼檔案和 CSS。

在前一章中審查 app.py 應用的 URL 對映時,其中有一個 static 路由。這是 Flask 為了支援靜態檔案而自動新增的,這個特殊路由的 URL 是 /static/。例如,呼叫 url_for('static', filename='css/styles.css', _external=True) 得到的結果是 http://localhost:5000/static/css/styles.css。

預設設定下,Flask 在應用根目錄中名為 static 的子目錄中尋找靜態檔案。如果需要,可在 static 資料夾中使用子資料夾存放檔案。伺服器收到對映到 static 路由上的 URL 後,生成的響應包含檔案系統中對應檔案裡的內容。

  1. 語法:url_for('static',filename='路徑')
  2. 可以載入css檔案,可以載入js檔案,還有image檔案。

第一個:載入css檔案

<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}"> 

第二個:載入js檔案

<script src="{{ url_for('static',filename='js/index.js') }}"></script> 

第三個:載入圖片檔案

<img src="{{ url_for('static',filename='images/zhiliao.png') }}" alt="">