第四章 前端模板(web UI)

模板是一個包含響應(yīng)文本的文件,其中包含用占位變量表示的動態(tài)部分,其具體值只在請求的上下文中才能知道。使用真實值替換變量,再返回最終得到的響應(yīng)字符串,這一過程稱為渲染。為了渲染模板,F(xiàn)lask使用了一個名為Jinja2的強大模板引擎。

4.1 Jinja2模板引擎

模板可以生成任何基于文本的格式(HTML、XML、CSV、LaTex 等等)。它并沒有特定的擴展名, .html或 .xml都是可以的。

模板包含 變量 或 表達式 ,這兩者在模板求值的時候會被替換為值。模板中 還有標簽,控制模板的邏輯。模板語法的大量靈感來自于 Django 和 Python 。

下面是一個最小的模板,它闡明了一些基礎(chǔ)。我們會在文檔中后面的部分解釋細節(jié):

<!DOCTYPE HTML>
 <html lang="zh">
   <head>
     <title>藕絲空間歡迎您! </title>
   </head>
    <body>
      <ul id="navigation">
        {% for item in navigation %}
          <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
        {% endfor %}
      </ul> 
      <h1>藕絲空間歡迎您! </h1>
      {{ a_variable }} 
    </body>
 </html>

這里有兩種分隔符: {% ... %}和 {{ ... }}。前者用于執(zhí)行諸如 for 循環(huán) 或賦值的語句,后者把表達式的結(jié)果打印到模板上。

4.1.1 模板變量

在模板中使用的{{ a }}結(jié)構(gòu)表示一個變量,它是一種特殊的占位符,告訴模板引擎這個位置的值從渲染模板時使用的數(shù)據(jù)中獲取。Jinja2 能識別所有類型的變量,甚至是一些復(fù)雜的類型,例如列表,字典和對象。在模板中使用的變量一些示例如下:

<p> 一個字典變量:{{ mydict['key'] }}。</p>
<p> 一個列表變量:{{ mylist['index'] }}。</p>
<p> 一個列表變量,并且?guī)в兴饕?{{ mylist['myintvar] }}。</p>
<p> 一個對象變量:{{ myobj.somemethod() }}。</p>

4.1.2 過濾器

變量可以通過 過濾器 修改。過濾器與變量用管道符號( |)分割,并且也 可以用圓括號傳遞可選參數(shù)。多個過濾器可以鏈式調(diào)用,前一個過濾器的輸出會被作為 后一個過濾器的輸入。

例如 {{ name|striptags|title }}會移除 name中的所有 HTML 標簽并且改寫 為標題樣式的大小寫格式。過濾器接受帶圓括號的參數(shù),如同函數(shù)調(diào)用。這個例子會把一個列表用逗號連接起來: {{ list|join(', ') }}。

下表列出了 Jinja2 提供的部分常用過濾器

過濾器名 說明
safe 渲染值時不轉(zhuǎn)義
capitalize 把值的首字母轉(zhuǎn)換成大寫,其它字母轉(zhuǎn)換成小寫
lower 把值轉(zhuǎn)換成小寫形式
upper 把值轉(zhuǎn)換成大寫形式
title 把值的每個單詞的首字母都轉(zhuǎn)換為大寫
trim 把值的首尾空格去掉
striptags 渲染之前把之中所有的 HTML 標簽都刪除

safe 過濾器值要特別說明一下。默認情況下,出于安全考慮,Jinja2 會轉(zhuǎn)義所有變量。例如,如果一個變量值為<h1>Hello</h1>,Jinja2 會將其渲染成&lt;h1&gt;Hello&lt;/h1&gt;瀏覽器能顯示這個 h1 元素,但不進行解釋。很多情況下需要顯示變量中存儲的 HTML 代碼,這時就可以使用 safe 過濾器。

4.1.3 注釋

要把模板中一行的部分注釋掉,默認使用 {# ... #} 注釋語法。這在調(diào)試或 添加給你自己或其它模板設(shè)計者的信息時是有用的:

{# note: disabled template because we no longer use this
   {% for user in users %}
       ...     
   {% endfor %}
#}

4.1.4 空白控制

默認配置中,模板引擎不會對空白做進一步修改,所以每個空白(空格、制表符、換行符 等等)都會原封不動返回。如果應(yīng)用配置了 Jinja 的 trim_blocks,模板標簽后的 第一個換行符會被自動移除(像 PHP 中一樣)。

此外,你也可以手動剝離模板中的空白。當你在塊(比如一個 for 標簽、一段注釋或變 量表達式)的開始或結(jié)束放置一個減號( -),可以移除塊前或塊后的空白:

{% for item in seq -%}
  {{ item }} 
{%- endfor %}

這會產(chǎn)出中間不帶空白的所有元素。如果 seq是 1到 9的數(shù)字的列表, 輸出會是123456789。

如果開啟了 行語句 ,它們會自動去除行首的空白。

提示:
標簽和減號之間不能有空白。

有效的:

 {%- if foo -%}
     ...
 {% endif %}

無效的:

 {% - if foo - %}
     ...
 {% endif %}

4.1.5 轉(zhuǎn)義

有時想要或甚至必要讓 Jinja 忽略部分,不會把它作為變量或塊來處理。例如,如果 使用默認語法,你想在在使用把 {{作為原始字符串使用,并且不會開始一個變量 的語法結(jié)構(gòu),你需要使用一個技巧。

最簡單的方法是在變量分隔符中( {{)使用變量表達式輸出:

{{ '{{' }}
對于較大的段落,標記一個塊為 raw是有意義的。例如展示 Jinja 語法的實例, 你可以在模板中用這個片段:

{% raw %}
  <ul>
    {% for item in seq %}
       <li>{{ item }}</li>
    {% endfor %}
  </ul> 
{% endraw %}

4.1.6 行語句

如果應(yīng)用啟用了行語句,就可以把一個行標記為一個語句。例如如果行語句前綴配置為 #,下面的兩個例子是等價的:

<ul>
 # for item in seq
   <li>{{ item }}</li>
 # endfor 
</ul> 
<ul>
 {% for item in seq %}
    <li>{{ item }}</li>
 {% endfor %} 
</ul>

行語句前綴可以出現(xiàn)在一行的任意位置,只要它前面沒有文本。為了語句有更好的可讀 性,在塊的開始(比如 for、 if、 elif等等)以冒號結(jié)尾:

# for item in seq:
  ... 
# endfor

提示:

若有未閉合的圓括號、花括號或方括號,行語句可以跨越多行:

<ul>
   # for href, caption in [('index.html', 'Index'),
               ('about.html', 'About')]:
      <li><a href="{{ href }}">{{ caption }}</a></li>
   # endfor 
</ul>

從 Jinja 2.2 開始,行注釋也可以使用了。例如如果配置 ##為行注釋前綴, 行中所有 ##之后的內(nèi)容(不包括換行符)會被忽略:

# for item in seq:
 <li>{{ item }}</li>   ## this comment is ignored 
# endfor

4.1.7 控制結(jié)構(gòu)

Jinja2提供了多種控制結(jié)構(gòu),可用來改變模板的渲染流程。

條件控制語句:

{% if user %}
   你好, {{ user }}!
{% endif %} 

循環(huán)控制語句及宏(宏類似于Python代碼中的函數(shù)):

{% macro render_comment(comment) %}
   <li>{{ comment }}</li>
{% endmacro %}
<ul>
   {% for comment in comments %}
     {{ render_comment(comment) }}
   {% endfor %}
</ul>

在一個 for 循環(huán)塊中你可以訪問這些特殊的變量:

變量 描述
loop.index 當前循環(huán)迭代的次數(shù)(從 1 開始)
loop.index0 當前循環(huán)迭代的次數(shù)(從 0 開始)
loop.revindex 到循環(huán)結(jié)束需要迭代的次數(shù)(從 1 開始)
loop.revindex0 到循環(huán)結(jié)束需要迭代的次數(shù)(從 0 開始)
loop.first 如果是第一次迭代,為 True 。
loop.last 如果是最后一次迭代,為 True 。
loop.length 序列中的項目數(shù)。
loop.cycle 在一串序列間期取值的輔助函數(shù)。見下面的解釋。

在 for 循環(huán)中,可以使用特殊的 loop.cycle 輔助函數(shù),伴隨循環(huán)在一個字符串/變 量列表中周期取值:

{% for row in rows %}
   <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}

重復(fù)使用宏的方法:

{% import 'macros.html' as macros %}
 <ul>
    {% for comment in comments %}
       {{ macros.render_comment(comment) }} 
    {% endfor %}
 </ul>

4.1.8 模板繼承

類似于Python代碼中的類繼承。首先創(chuàng)建一個名為base.html的基模板:

<html>
    <head>
    {% block head %}
        <title>{% block title %}{% endblock %} - 我的程序</title>
    {% endblock %}
    </head>
    <body>
       {% block body %}
       {% endblock %}
    </body>
</html>

基模板的衍生模板:

 {% extends 'base.html' %}
 {% block title %}首頁{% endblock %}
 {% block head %}
     {{ super() }} 
     <style>
     </style>
 {% endblock %}
 {% block body %}
     <h1>你好,世界!</h1>
 {% endblock %}

extents指令聲明這個模板衍生自base.html。在extents指令之后,基模板中的3個塊被重新定義,模板引擎會將其插入適當?shù)奈恢?。super()函數(shù)用來獲取基模板原來的內(nèi)容。

4.2 在程序中配置bootstrap模板

要想在程序中集成Bootstrap,顯然要對模板做必要的改動。有一個更簡單的方法是使用一個名為Flask-Bootstrap的Flask擴展,簡化集成過程。

(flask)$ pip install flask-bootstrap

不過由于上述插件功能有限,推薦使用自己配置的Bootstrap模板。

將bootstrap模板中的核心css文件 bootstrap.min.css 和主題css文件bootstrap-theme.mim.css復(fù)制到 靜態(tài)文件夾static 的 static/css文件夾里,同時將字體文件復(fù)制到static/fonts文件夾里;將jquery核心js文件jquery.min.js和bootstrap的js文件bootstrap.min.js文件復(fù)制到static/js文件夾里。同時,你可以將自己的個性化模板所用用到的css和js文件復(fù)制到相應(yīng)的文件夾里。

4.3 渲染模板

默認情況下,Flask 在程序文件夾中的 templates 子文件夾中尋找模板。在下一個hello.py版本中,要把已定義的模板保存在templates文件夾中,并分別命名為index.html和user.html。
示例 4-2 hello.py:渲染模板

 from flask import Flask, render_template
 # …
 @app.route('/')
 def index():
     return render_template('index.html')
 @app.route('/user/<name>')
 def user(name):
     return render_template('user.html', name=name)

Flask提供的render_template函數(shù)把Jinja2模板引擎集成到了程序中。render_template函數(shù)第一個參數(shù)是模板的文件名。隨后的參數(shù)都是鍵值對,表示模板中變量對應(yīng)的真實值。

啟動你的項目:

(flask)$ python hello.py

這時你應(yīng)該可以看到你自己的網(wǎng)頁了。

最后,請發(fā)揮你的想象力,利用bootstrap的前端技術(shù),來充分個性化你的頁面吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容