Jinja2 模板的學(xué)習(xí)

默認(rèn)情況下,F(xiàn)lask 在程序文件夾中的 templates 子文件夾中尋找模板。在下一個(gè) hello.py 版本中,要把前面定義的模板保存在 templates 文件夾中,并分別命名為 index.html 和 user.html。

index.thm的代碼如下,不傳參數(shù)

<html>
    <head>
        <title>歡迎來(lái)到王者榮耀</title> 
    </head>
    <body>
        <p>你是不是要成為一個(gè)高手</p>
    </body>

</html>

user.html中傳遞一個(gè)參數(shù)

<html>
    <head>
        <title>歡迎來(lái)到王者榮耀</title> 
    </head>
    <body>
        <p>你是不是要成為一個(gè)高手,你的名字是{{name}}</p>
    </body>

</html>

在hello.py中,

from flask import render_template
@app.route('/')
def index():
    return render_template('index.html')
@app.route('/user/<name>') #尖括號(hào)中的動(dòng)態(tài)名字
def user(name):
    return render_template('user.html',name=name)

1、變量

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

     <p>A value from a dictionary: {{ mydict['key'] }}.</p>
     <p>A value from a list: {{ mylist[3] }}.</p>
     <p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p>
     <p>A value from an object's method: {{ myobj.somemethod() }}.</p>

可以使用過(guò)濾器修改變量,過(guò)濾器名添加在變量名之后,中間使用豎線分隔。例如,下述 模板以首字母大寫形式顯示變量 name 的值:

Hello, {{ name|capitalize }}

下面是常用的過(guò)濾器

8568F68D-6315-4E2D-88A3-205D6C011941.png

更多的fliter官方文檔

2、Jinja2的控制結(jié)構(gòu)

if - else 的寫法

    {% if name %}
        Hello,{{name}}
    {% else %}
        Hello ,你沒名字一看就是菜啊!!!
    {% endif %}

for 循環(huán)

    {% for title in ["黃金4","黃金3","黃金2"] %}
        <li>{{title}}</li>
    {% endfor %}

Jinja2 還支持宏。宏類似于 Python 代碼中的函數(shù)。例如:

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

為了重復(fù)使用宏,我們可以將其保存在單獨(dú)的文件中,然后在需要使用的模板中導(dǎo)入:

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

需要在多處重復(fù)使用的模板代碼片段可以寫入單獨(dú)的文件,再包含在所有模板中,以避免 重復(fù):

{% include 'common.html' %}

另一種重復(fù)使用代碼的強(qiáng)大方式是模板繼承,它類似于 Python 代碼中的類繼承。首先,創(chuàng)
建一個(gè)名為 base.html 的基模板:

<html>
    <head>
        {% block head %}
        <title>{% block title %}{% endblock %} - MyApplication</title>
        {% endblock %}
    </head>
    <body>
        {%block body %}
        <p>我是來(lái)自基類</p>
        {%endblock %}
    </body>

</html>

新建一個(gè)son.html 繼承base.html

{% extends "base.html" %}
{% block title %} INDEX {% endblock %}
{% block head %}
    {{super()}}
{% endblock %}
{% block body %}
{{super()}}
<h1>我也是醉了,這是啥基礎(chǔ)自基礎(chǔ)模板</h1>
{% endblock %}

extends 指令聲明這個(gè)模板衍生自 base.html。在 extends 指令之后,基模板中的 3 個(gè)塊被 重新定義,模板引擎會(huì)將其插入適當(dāng)?shù)奈恢?。注意新定義的 head 塊,在基模板中其內(nèi)容不 是空的,所以使用 super() 獲取原來(lái)的內(nèi)容。

3、自定義錯(cuò)誤頁(yè)面的方式

自定義錯(cuò)誤頁(yè)面
     @app.errorhandler(404)
     def page_not_found(e):
         return render_template('404.html'), 404
     @app.errorhandler(500)
     def internal_server_error(e):
         return render_template('500.html'), 500

4、鏈接

任何具有多個(gè)路由的程序都需要可以連接不同頁(yè)面的鏈接,例如導(dǎo)航條。
在模板中直接編寫簡(jiǎn)單路由的 URL 鏈接不難,但對(duì)于包含可變部分的動(dòng)態(tài)路由,在模板 中構(gòu)建正確的 URL 就很困難。而且,直接編寫 URL 會(huì)對(duì)代碼中定義的路由產(chǎn)生不必要的 依賴關(guān)系。如果重新定義路由,模板中的鏈接可能會(huì)失效。
為了避免這些問(wèn)題,F(xiàn)lask 提供了 url_for() 輔助函數(shù),它可以使用程序 URL 映射中保存 的信息生成 URL。
url_for() 函數(shù)最簡(jiǎn)單的用法是以視圖函數(shù)名(或者 app.add_url_route() 定義路由時(shí)使用 的端點(diǎn)名)作為參數(shù),返回對(duì)應(yīng)的 URL。例如,在當(dāng)前版本的 hello.py程序中調(diào)用 url_ for('index')得到的結(jié)果是/。調(diào)用url_for('index', _external=True)返回的則是絕對(duì)地 址,在這個(gè)示例中是 http://localhost:5000/
生成連接程序內(nèi)不同路由的鏈接時(shí),使用相對(duì)地址就足夠了。如果要生成在 瀏覽器之外使用的鏈接,則必須使用絕對(duì)地址,例如在電子郵件中發(fā)送的 鏈接。
使用 url_for() 生成動(dòng)態(tài)地址時(shí),將動(dòng)態(tài)部分作為關(guān)鍵字參數(shù)傳入。例如,url_for ('user', name='john', _external=True) 的返回結(jié)果是 http://localhost:5000/user/john
傳入 url_for() 的關(guān)鍵字參數(shù)不僅限于動(dòng)態(tài)路由中的參數(shù)。函數(shù)能將任何額外參數(shù)添加到 查詢字符串中。例如,url_for('index', page=2) 的返回結(jié)果是 /?page=2。

5、靜態(tài)文件

Web 程序不是僅由 Python 代碼和模板組成。大多數(shù)程序還會(huì)使用靜態(tài)文件,例如 HTML
代碼中引用的圖片、JavaScript 源碼文件和 CSS。
例如,調(diào)用 url_for('static', filename='css/styles.css', _external=True) 得 到 的 結(jié) 果 是 http:// localhost:5000/static/css/styles.css。
默認(rèn)設(shè)置下,F(xiàn)lask 在程序根目錄中名為 static 的子目錄中尋找靜態(tài)文件。如果需要,可在 static 文件夾中使用子文件夾存放文件。服務(wù)器收到前面那個(gè) URL 后,會(huì)生成一個(gè)響應(yīng), 包含文件系統(tǒng)中 static/css/styles.css 文件的內(nèi)容。

6、使用Flask-Moment本地化日期和時(shí)間

有一個(gè)使用 JavaScript 開發(fā)的優(yōu)秀客戶端開源代碼庫(kù),名為 moment.js(http://momentjs. com/),它可以在瀏覽器中渲染日期和時(shí)間。Flask-Moment 是一個(gè) Flask 程序擴(kuò)展,能把 moment.js 集成到 Jinja2 模板中。Flask-Moment 可以使用 pip 安裝:

 pip3 install flask-moment

這個(gè)擴(kuò)展的初始化方法如示例 3-11 所示。 示例 3-11 hello.py:初始化 Flask-Moment

from flask.ext.moment import Moment moment = Moment(app)

7、使用Flask-Bootstrap集成Twitter Bootstrap

安裝

 pip3 install flask-bootstrap

初始化 Flask-Bootstrap

from flask_bootstrap import Bootstrap
bootstrap = Bootstrap(app)

新建一個(gè)home.html模板,繼承bootstrap的base.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 %}

Flask-Bootstrap 的 base.html 模板還定義了很多其他塊,都可在衍生模板中使用。表 3-2 列

![Uploading 18C6212F-F78C-4AA2-8281-9FAB2C5FC341_474250.png . . .]
18C6212F-F78C-4AA2-8281-9FAB2C5FC341.png

上圖中很多塊都是 Flask-Bootstrap 自用的,如果直接重定義可能會(huì)導(dǎo)致一些問(wèn)題。例 如,Bootstrap 所需的文件在 styles 和 scripts 塊中聲明。如果程序需要向已經(jīng)有內(nèi)容的塊 中添加新內(nèi)容,必須使用 Jinja2 提供的 super() 函數(shù)。例如,如果要在衍生模板中添加新 的 JavaScript 文件,需要這么定義 scripts 塊:

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

7、web表單

盡管 Flask 的請(qǐng)求對(duì)象提供的信息足夠用于處理 Web 表單,但有些任務(wù)很單調(diào),而且要重 復(fù)操作。比如,生成表單的 HTML 代碼和驗(yàn)證提交的表單數(shù)據(jù)。
Flask-WTF(http://pythonhosted.org/Flask-WTF/)擴(kuò)展可以把處理 Web 表單的過(guò)程變成一 種愉悅的體驗(yàn)。這個(gè)擴(kuò)展對(duì)獨(dú)立的 WTForms(http://wtforms.simplecodes.com)包進(jìn)行了包 裝,方便集成到 Flask 程序中。
Flask-WTF 及其依賴可使用 pip 安裝:

pip3 install flask-wtf

默認(rèn)情況下,F(xiàn)lask-WTF能保護(hù)所有表單免受跨站請(qǐng)求偽造(Cross-Site Request Forgery,
CSRF)的攻擊。惡意網(wǎng)站把請(qǐng)求發(fā)送到被攻擊者已登錄的其他網(wǎng)站時(shí)就會(huì)引發(fā) CSRF 攻擊。 為了實(shí)現(xiàn) CSRF 保護(hù),F(xiàn)lask-WTF 需要程序設(shè)置一個(gè)密鑰。Flask-WTF 使用這個(gè)密鑰生成
加密令牌,再用令牌驗(yàn)證請(qǐng)求中表單數(shù)據(jù)的真?zhèn)?。設(shè)置密鑰的方法設(shè)置 Flask-WTF

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
   33

app.config 字典可用來(lái)存儲(chǔ)框架、擴(kuò)展和程序本身的配置變量。使用標(biāo)準(zhǔn)的字典句法就能 把配置值添加到 app.config 對(duì)象中。這個(gè)對(duì)象還提供了一些方法,可以從文件或環(huán)境中導(dǎo) 入配置值。
SECRET_KEY 配置變量是通用密鑰,可在 Flask 和多個(gè)第三方擴(kuò)展中使用。如其名所示,加 密的強(qiáng)度取決于變量值的機(jī)密程度。不同的程序要使用不同的密鑰,而且要保證其他人不 知道你所用的字符串。

表單類:
使用 Flask-WTF 時(shí),每個(gè) Web 表單都由一個(gè)繼承自 Form 的類表示。這個(gè)類定義表單中的 一組字段,每個(gè)字段都用對(duì)象表示。字段對(duì)象可附屬一個(gè)或多個(gè)驗(yàn)證函數(shù)。驗(yàn)證函數(shù)用來(lái) 驗(yàn)證用戶提交的輸入值是否符合要求。
下面是一個(gè)簡(jiǎn)單的 Web 表單,包含一個(gè)文本字段和一個(gè)提交按鈕。

from flask_wtf import Form
from wtforms import StringField, SubmitField 
from wtforms.validators import Required
class NameForm(Form):
    name = StringField('What is your name?', validators=[Required()]) 
    submit = SubmitField('Submit')

這個(gè)表單中的字段都定義為類變量,類變量的值是相應(yīng)字段類型的對(duì)象。在這個(gè)示例中, NameForm 表單中有一個(gè)名為 name 的文本字段和一個(gè)名為 submit 的提交按鈕。StringField 類表示屬性為 type="text" 的 <input> 元素。SubmitField 類表示屬性為 type="submit" 的 <input> 元素。字段構(gòu)造函數(shù)的第一個(gè)參數(shù)是把表單渲染成 HTML 時(shí)使用的標(biāo)號(hào)。
StringField 構(gòu)造函數(shù)中的可選參數(shù) validators 指定一個(gè)由驗(yàn)證函數(shù)組成的列表,在接受 用戶提交的數(shù)據(jù)之前驗(yàn)證數(shù)據(jù)。驗(yàn)證函數(shù) Required() 確保提交的字段不為空。

WTForms 支持的 HTML 標(biāo)準(zhǔn)字段如下圖

9278B3CA-AF23-4D0D-82F1-069F17A27188.png

WTForms 內(nèi)建的驗(yàn)證函數(shù)

3A0C9B81-7C18-404B-AC94-6E71EDE4FEE5.png

把表單類渲染為HTML
例通過(guò)參數(shù) form 傳入模板,在模板中可以生成一個(gè)簡(jiǎn)單的表單,如下所示:

     <form method="POST">
         {{ form.hidden_tag() }}
         {{ form.name.label }} {{ form.name() }}
         {{ form.submit() }}
    </form>

即便能指定 HTML 屬性,但按照這種方式渲染表單的工作量還是很大,所以在條件允許的 情況下最好能使用 Bootstrap 中的表單樣式。Flask-Bootstrap 提供了一個(gè)非常高端的輔助函 數(shù),可以使用 Bootstrap 中預(yù)先定義好的表單樣式渲染整個(gè) Flask-WTF 表單,而這些操作 只需一次調(diào)用即可完成。使用 Flask-Bootstrap,上述表單可使用下面的方式渲染:

{% import "bootstrap/wtf.html" as wtf %}
 {{ wtf.quick_form(form) }}

Flash消息
請(qǐng)求完成后,有時(shí)需要讓用戶知道狀態(tài)發(fā)生了變化。這里可以使用確認(rèn)消息、警告或者錯(cuò) 誤提醒。一個(gè)典型例子是,用戶提交了有一項(xiàng)錯(cuò)誤的登錄表單后,服務(wù)器發(fā)回的響應(yīng)重新 渲染了登錄表單,并在表單上面顯示一個(gè)消息,提示用戶用戶名或密碼錯(cuò)誤。
這種功能是 Flask 的核心特性。

@app.route('/',methods = ['GET','POST'])
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        
        old_name = session.get('name')
        new_name = form.name.data
        session['name'] = new_name
        if old_name is not None and old_name != new_name:
            flash('你似乎改變了你的名字')
        return redirect(url_for('index'))
        
    return render_template('testForm.html', form=form, name=session.get('name'))

在這個(gè)示例中,每次提交的名字都會(huì)和存儲(chǔ)在用戶會(huì)話中的名字進(jìn)行比較,而會(huì)話中存儲(chǔ) 的名字是前一次在這個(gè)表單中提交的數(shù)據(jù)。如果兩個(gè)名字不一樣,就會(huì)調(diào)用 flash() 函數(shù), 在發(fā)給客戶端的下一個(gè)響應(yīng)中顯示一個(gè)消息。

獲取get_flashed_messages()來(lái)獲取消息
在html中顯示消息

{% for message in get_flashed_messages() %}
        <div class="alert alert-waring">
            <button type="button" class="close" data-dismiss="alert">&times;</button>
            {{message}}
        </div>
{% endfor %}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 22年12月更新:個(gè)人網(wǎng)站關(guān)停,如果仍舊對(duì)舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,394評(píng)論 22 257
  • 第三章 模板 序 為什么要分離 易于維護(hù)的代碼,關(guān)鍵在于保持簡(jiǎn)單的結(jié)構(gòu)。而我們之前編寫的hello.py雖然簡(jiǎn)單,...
    科幻經(jīng)典閱讀 1,610評(píng)論 0 6
  • 第4章 Web表單 我們?cè)诘诙陆榻B過(guò)請(qǐng)求對(duì)象,它包含有客戶端請(qǐng)求的全部信息。尤其是,可以通過(guò)request.fo...
    易木成華閱讀 1,127評(píng)論 0 1
  • 請(qǐng)求對(duì)象包含客戶端發(fā)出的所有請(qǐng)求信息。其中 request.form 能獲取 POST 請(qǐng)求中提交的表單數(shù)據(jù)。 我...
    焉知非魚閱讀 1,185評(píng)論 0 2
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評(píng)論 19 139

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