轉載請在文章開頭附上原文連接地址:http://www.javashuo.com/article/p-fbvavmqk-hy.htmlhtml
Flask內置的模板語言,它的設計思想來源於 Django 的模板引擎,並擴展了其語法和一系列強大的功能。python
渲染模版函數sql
from flask import Flask, render_template @app.route('/') def index(): return render_template('index.html')
templates
文件夾,用於存放全部的模板文件,並在目錄下建立一個模板html文件 index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 個人模板html內容 </body> </html>
{{}} 來表示變量名,這種 {{}} 語法叫作變量代碼塊flask
視圖代碼:後端
@app.route("/") def index(): title = "網頁標題" return render_template("index.html",title=title)
模板代碼api
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{title}}</title> </head> <body> <h1>{{title}}</h1> </body> </html>
Jinja2 模版中的變量代碼塊能夠是任意 Python 類型或者對象,只要它可以被 Python 的 str() 方法轉換爲一個字符串就能夠,好比,能夠經過下面的方式顯示一個字典或者列表中的某個元素:安全
{{your_dict['key']}} {{your_list[0]}}
用 {%%} 定義的控制代碼塊,能夠實現一些語言層次的功能,好比循環或者if語句session
{% if user %} {{ user }} {% else %} hello! <ul> {% for index in indexs %} <li> {{ index }} </li> {% endfor %} </ul>
使用 {# #} 進行註釋,註釋的內容不會在html中被渲染出來app
{# {{ name }} #}
你能夠在本身的模板中訪問一些 Flask 默認內置的函數和對象xss
你能夠從模板中直接訪問Flask當前的config對象:
{{config.SQLALCHEMY_DATABASE_URI}} sqlite:///database.db
就是flask中表明當前請求的request對象:
{{request.url}} http://127.0.0.1
爲Flask的session對象
{{session.new}} True
在視圖函數中設置g變量的 name 屬性的值,而後在模板中直接能夠取出
{{ g.name }}
url_for會根據傳入的路由器函數名,返回該路由對應的URL,在模板中始終使用url_for()就能夠安全的修改路由綁定的URL,則不比擔憂模板中渲染出錯的連接:
{{url_for('home')}}
若是咱們定義的路由URL是帶有參數的,則能夠把它們做爲關鍵字參數傳入url_for(),Flask會把他們填充進最終生成的URL中:
{{ url_for('post', post_id=1)}} /post/1
主要包含兩個:
- if/else if /else / endif - for / endfor
Jinja2 語法中的if語句跟 Python 中的 if 語句類似,後面的布爾值或返回布爾值的表達式將決定代碼中的哪一個流程會被執行:
{%if user.is_logged_in() %} <a href='/logout'>Logout</a> {% else %} <a href='/login'>Login</a> {% endif %}
過濾器能夠被用在 if 語句中:
{% if comments | length > 0 %} There are {{ comments | length }} comments {% else %} There are no comments {% endif %}
{% for post in posts %} <div> <h1>{{ post.title }}</h1> <p>{{ post.text | safe }}</p> </div> {% endfor %}
{% for post in posts if post.text %} <div> <h1>{{ post.title }}</h1> <p>{{ post.text | safe }}</p> </div> {% endfor %}
變量 | 描述 |
---|---|
loop.index | 當前循環迭代的次數(從 1 開始) |
loop.index0 | 當前循環迭代的次數(從 0 開始) |
loop.revindex | 到循環結束須要迭代的次數(從 1 開始) |
loop.revindex0 | 到循環結束須要迭代的次數(從 0 開始) |
loop.first | 若是是第一次迭代,爲 True 。 |
loop.last | 若是是最後一次迭代,爲 True 。 |
loop.length | 序列中的項目數。 |
loop.cycle | 在一串序列間期取值的輔助函數。見下面示例程序。 |
{% for post in posts%} {{loop.index}}, {{post.title}} {% endfor %}
1, Post title 2, Second Post
{% for post in posts%} {{loop.cycle('odd','even')}} {{post.title}} {% endfor %}
odd Post Title even Second Post
過濾器的本質就是函數。有時候咱們不只僅只是須要輸出變量的值,咱們還須要修改變量的顯示,甚至格式化、運算等等,而在模板中是不能直接調用 Python 中的某些方法,那麼這就用到了過濾器。
使用方式:
{{variable | filter_name(*args)}}
{{variable | filter_name }}
在 jinja2 中,過濾器是能夠支持鏈式調用的,示例以下:
{{ "hello world" | reverse | upper }}
<p>{{ '<em>hello</em>' | safe }}</p>
<p>{{ 'hello' | capitalize }}</p>
<p>{{ 'HELLO' | lower }}</p>
<p>{{ 'hello' | upper }}</p>
<p>{{ 'hello' | title }}</p>
<p>{{ 'olleh' | reverse }}</p>
<p>{{ '%s is %d' | format('name',17) }}</p>
<p>{{ '<em>hello</em>' | striptags }}</p>
<p>{{ 'hello every one' | truncate(9)}}</p>
<p>{{ [1,2,3,4,5,6] | first }}</p>
<p>{{ [1,2,3,4,5,6] | last }}</p>
<p>{{ [1,2,3,4,5,6] | length }}</p>
<p>{{ [1,2,3,4,5,6] | sum }}</p>
<p>{{ [6,2,3,1,5,4] | sort }}</p>
{% filter upper %} #一大堆文字# {% endfilter %}
過濾器的本質是函數。當模板內置的過濾器不能知足需求,能夠自定義過濾器。自定義過濾器有兩種實現方式:
重要:自定義的過濾器名稱若是和內置的過濾器重名,會覆蓋內置的過濾器。
需求:添加列表反轉的過濾器
方式一
經過調用應用程序實例的 add_template_filter 方法實現自定義過濾器。該方法第一個參數是函數名,第二個參數是自定義的過濾器名稱:
def do_listreverse(li): # 經過原列表建立一個新列表 temp_li = list(li) # 將新列表進行返轉 temp_li.reverse() return temp_li app.add_template_filter(do_listreverse,'lireverse')
方式二
用裝飾器來實現自定義過濾器。裝飾器傳入的參數是自定義的過濾器名稱。
@app.template_filter('lireverse') def do_listreverse(li): # 經過原列表建立一個新列表 temp_li = list(li) # 將新列表進行返轉 temp_li.reverse() return temp_li
<br/> my_array 原內容:{{ my_array }} <br/> my_array 反轉:{{ my_array | lireverse }}
my_array 原內容:[3, 4, 2, 1, 7, 9] my_array 反轉:[9, 7, 1, 2, 4, 3]
在模板中,可能會遇到如下狀況:
像遇到這種狀況,可使用 JinJa2 模板中的 繼承 來進行實現
模板繼承是爲了重用模板中的公共內容。通常Web開發中,繼承主要使用在網站的頂部菜單、底部。這些內容能夠定義在父模板中,子模板直接繼承,而不須要重複書寫。
{% block top %} {% endblock %}
父模板代碼:
base.html
{% block top %} 頂部菜單 {% endblock top %} {% block content %} {% endblock content %} {% block bottom %} 底部 {% endblock bottom %}
子模板代碼:
{% extends 'base.html' %} {% block content %} 須要填充的內容 {% endblock content %}
模板繼承使用時注意點:
config.py
class Config(object): DEBUG = True SECRET_KEY = "abcccddgadsag"
main.py
from flask import Flask from config import Config from flask import render_template app = Flask(__name__,template_folder='templates') app.config.from_object(Config) from flask import session @app.route("/set_session") def set_session(): session["username"] = 'request數據' return "ok" from flask import g @app.route("/") def index(): title = "網頁標題" dict1 = {"id":1,"username":"xiaoming","money":20.5} love = ['睡覺','吹牛','敲代碼'] g.list1 = ['睡覺','吹牛','敲代碼'] g.book_list = [ {"id":1,"name":"浪潮之巔","price":88.5}, {"id":12,"name":"數學之美","price":68.5}, {"id":12,"name":"數學之美","price":68.5}, {"id":12,"name":"數學之美","price":68.5}, {"id":13,"name":"硅谷之謎","price":108.533333}, {"id":14,"name":"五年高考三年模擬","price":78.5}, ] g.title2 = '<script>alert("大標題")</script>' g.question = '若是x=10,x<y,y>z,求z的取值範圍?' return render_template("index.html",title=title,dict1=dict1,love=love) """自定義過濾器""" def rev(data): data.reverse() return data app.add_template_filter(rev,'myrev') @app.route("/filter") def myfilter(): g.list1 = ['睡覺', '吹牛', '敲代碼'] return render_template("f.html") if __name__ == '__main__': app.run()
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{title}}</title> </head> <body> <h1>{{title}}</h1> <table border="1" width="400"> <tr> <th>ID</th> <th>姓名</th> <th>存款</th> </tr> <tr> <td>{{ dict1["id"] }}</td> <td>{{ dict1["username"] }}</td> <td>{{ dict1["money"] }}</td> </tr> <tr> <td>{{ dict1.id }}</td> <td>{{ dict1.username }}</td> <td>{{ dict1.money }}</td> </tr> </table> <ul> <li>{{ love.0 }}</li> <li>{{ love.1 }}</li> <li>{{ love.2 }}</li> <li>{{ love[0] }}</li> <li>{{ love[1] }}</li> <li>{{ love[2] }}</li> {# for循環也支持多層的嵌套或者其餘語句 #} {% for item in love %} <li>{{ item }}</li> {% endfor %} </ul> {# 這裏是if判斷,if還能夠支持多個條件的判斷 #} {% if dict1.money < 20 %} <p>存款太少了,須要充值</p> {% endif %} {# 特殊變量 #} {# 支持直接讀取配置信息 #} <p>{{ config.SECRET_KEY }}</p> {# 支持獲取請求信息 #} <p>{{ request.method }}</p> {# 支持獲取session數據 #} <p>{{ session.username }}</p> {# 支持獲取g變量 #} <p>{{ g.list1 }}</p> {# 支持使用url_for生成地址 #} <a href="{{ url_for("set_session") }}">跳轉到sesion</a> {# for循環中還內置了循環對象loop,能夠操做循環過程當中的索引 #} <table border="1" width="600"> <tr> <th>序號</th> <th>ID</th> <th>書名</th> <th>價格</th> </tr> {% for book in g.book_list %} {% if loop.first %} <tr style="background-color: orange;"> {% elif loop.last %} <tr style="background-color: blue;color: #fff;"> {% else %} <tr> {% endif %} <td>{{ loop.revindex }}</td> <td>{{ "%03d" % book.id }}</td> <td>{{ book.name }}</td> <td>{{ book.price }}</td> </tr> {% endfor %} </table> {# 過濾器 #} {{ dict1.username | upper | reverse }} {# 默認狀況下, flask會自動針對html標籤進行實體化轉移,目的時爲了防止xss攻擊 可是,咱們後端也會有一些包含樣式的內容要輸出頁面中,此時可使用 safe 過濾器 #} {{ g.title2 | safe }} {# 這個過濾器會直接刪除html標籤,也是爲了防止xss攻擊,可是這個過濾器慎用,在遇到數學公式的時候,會誤傷. #} {{ g.title2 | striptags }} {{ g.question | striptags }} {# 字符長度截取 #} <p>{{ 'hello every one' | truncate(9)}}</p> {% filter upper %} dasdasd dsa das ds ad <p>{{ 'hello every one' | truncate(9)}}</p> asd asdas {% endfilter %} {{ "hwello" }} </body> </html>
在 Flask 中, Flask-wtf 擴展有一套完善的 csrf 防禦體系,對於咱們開發者來講,使用起來很是簡單
1 設置應用程序的 secret_key,用於加密生成的 csrf_token 的值
# session加密的時候已經配置過了.若是沒有在配置項中設置,則以下: app.secret_key = "#此處能夠寫隨機字符串#"
2 導入 flask_wtf.csrf 中的 CSRFProtect 類,進行初始化,並在初始化的時候關聯 app
from flask.ext.wtf import CSRFProtect CSRFProtect(app)
3 在表單中使用 CSRF 令牌:
<form method="post" action="/"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" /> </form>