7、Flask实战第7天:Jinjia2模板
Jinja2模板介紹和查找路徑
在前面的章節中,視圖只是直接返回文本,然而在實際生產環境中其實很少這樣用,因為實際的頁面大多帶有樣式和復雜邏輯的HTML代碼,這可以讓瀏覽器其渲染出非常漂亮的頁面。
我們創建好flask項目,會發現有一個templates目錄,這個目錄就是用來存放模板文件
如果我們要使用模板,則需要導入render_template模塊
我們先在templates目錄下創建模板文件index.html,內容如下:
<h3>I love python</h3>然后我們來渲染使用這個模板
... from flask import render_template@app.route('/') def index():return render_template('index.html')模板的路徑是相對于templates的,如果這個模板路徑是templates/posts/lists.html,那么路徑應該這樣寫:
render_template('posts/lists.html')我們可以看看為什么flask如何把templates作為模板路徑的
按住ctrl,鼠標點擊app = Flask(__name__)中的Flask,可以發現這個類默認有個參數template_folder='templates'
因此,如果我們不想把templates作為模板目錄的話,比如用/home/heboan/haha這個目錄,我們可以這樣
app = Flask(__name__, template_folder='/home/heboan/haha')?
模板傳參及其技巧
視圖函數如下,傳入參數username
@app.route('/') def index():return render_template('index.html', username='何波安')模板文件index.html如下: 使用{{ 變量名 }}的方式引用
<body>姓名:{{ username }}</body>如果傳入多個變量,可以這樣寫:
@app.route('/') def index():return render_template('index.html', username='何波安', age=18, job='coder')但是當參數很多的時候,這樣就不方便了,我們可以用字典的方式來傳參
@app.route('/') def index():context = {'username': '何波安','age': 18,'job': 'coder'}return render_template('index.html', context=context)這樣的話,我們模板就需要用context.username這種方式寫
<body>姓名:{{ context.username }} <br />年齡:{{ context.age }} <br />工作:{{ context.job }}</body>如果我們想直接用username直接接收變量,我們可以這樣做:把字典當成關鍵字參數
@app.route('/') def index():context = {'username': '何波安','age': 18,'job': 'coder'}return render_template('index.html', **context)這樣,我們就可以直接使用參數變量了
<body>姓名:{{ username }} <br />年齡:{{ age }} <br />工作:{{ job }}</body>如果參數的值也是字典
@app.route('/') def index():context = {'username': '何波安','age': 18,'job': 'coder','attribute': {'height': '180cm','weight': '80kg'}}return render_template('index.html', **context)那么模板可以這樣引用
<body>姓名:{{ username }} <br />年齡:{{ age }} <br />工作:{{ job }} <br />身高:{{ attribute.height }} <br />體重: {{ attribute.weight }}</body>?
模板中使用url_for
模板里面有很多超鏈接,比如
@app.route('/login/') def login():return render_template('login.html')模板index.html
<a href="/login/">登錄</a>但是在實際開發中是不會寫死的,這樣不方便后期維護,這時候我們就可以用到url_for
<a href="{{ url_for('login') }}">登錄</a>如果需要傳遞參數,如
@app.route('/login/<user_id>') def login(user_id):return render_template('login.html')模板index.html
<a href="{{ url_for('login', user_id='1') }}">登錄</a>?
過濾器
過濾器是通過管道符號"|"進行使用的,例如: {{ name| length }},將返回name的長度。過濾器相當于是一個函數,把當前的變量傳入過濾器中,然后過濾器根據自己的功能,再返回相應的值,之后再將結果渲染到頁面中。
基本用法
@app.route('/') def index():return render_template('index.html', position=-2)index.html
position的絕對值是: {{ position|abs }}default過濾器
{{ <變量名>|default('默認值', boolean=True)}}
場景: 當用戶沒有自定義個性簽名的時候,使用default傳遞值,如下:
@app.route('/') def index():context = {'signature': '世界真的好贊'}return render_template('index.html', **context)index.html
個性簽名: {{ signature|default('這個人真懶,什么都沒有留下~') }}個性簽名字段signature存在,因此會顯示"世界真的好贊"
當沒有定義signature,則會顯示"這個人真懶,什么都沒有留下~"
@app.route('/') def index():context = {#'signature': '世界真的好贊' }return render_template('index.html', **context)當定義signature為None時,看看如何顯示
@app.route('/') def index():context = {'signature': None}return render_template('index.html', **context)我們發現,顯示的并不是default的值,而是None,這是為什么呢?
這是因為我們默認的default值只有變量不存在的時候才會引用,如果變量存在,那么就不會使用它
我們知道:None,空字符串,空字典,空列表等在布爾值都是False
如果我們想要在變量的布爾值是False的情況下就使用default的值,可以加上參數
個性簽名: {{ signature|default('這個人真懶,什么都沒有留下~', boolean=True) }}還有一種簡寫方式
個性簽名: {{ signature or '這個人真懶,什么都沒有留下~' }}?
escape字符轉義
看如下例子
@app.route('/') def index():context = {'signature': '<h1>世界真的好贊</h1>'}return render_template('index.html', **context)index.html
個性簽名: {{ signature }}我們發現jinjia2自動把signature當做普通字符串處理了(為了安全性)
我們可以關閉自動處理,在{% autoescape off %}里面的內容是不會被jinjia2模板自動處理的
{% autoescape off %}個性簽名: {{ signature }} {% endautoescape %}還有另外一種方法就是使用safe
個性簽名: {{ signature| safe}}在{% autoescape off %}里面的內容我們又想被轉義處理,就可以使用escape了
{% autoescape off%}個性簽名: {{ signature| escape}} {% endautoescape %} last(value): 返回一個序列的最后一個元素。示例: names|last lenth(value): 返回一個序列或者字典的長度。 示例:names|lenth join(value, d=u''): 講一個序列用d這個參數的值拼接成字符串 int(value): 將值轉換為int類型 float(value): 將值轉換為float類型 lower(value): 將字符串轉換為小寫 upper(value):將字符串轉換為大寫 replace(value, old, new): 替換將old替換為new的字符串 truncate(value,length=255, killwords=False): 截取length長度的字符串 trim: 截取字符串前后的空白字符 string(value): 將變量轉換成字符串 wordcount(s): 計算一個長字符串中單詞的個數 其他常用的過濾器?
自定義過濾器
自定義過濾器其實就是定義函數,比如我要定義一個cut過濾器,這個過濾器實現的功能是把變量值里面的hello全部去掉
@app.route('/') def index():context = {'article': 'hello, this is test hello world'}return render_template('index.html', **context)@app.template_filter('cut') #把cut函數注冊到過濾器中 def cut(value): #value就是使用過濾器的變量value = value.replace('hello', '')return value #函數的返回值會作為過濾器的返回值index.html
{{ article|cut }}?
自定義事件處理過濾器案例
在實際案例中,我們會看到這種情況,顯示內容發表的時間,比如微信。現在我們來自定義一個過濾器來實現這樣的需求:
發表時間距離現在的時間間隔:
1、如果時間間隔在1分鐘以內,顯示‘剛剛’
2、如果大于1分鐘小于1小時,顯示‘xx分鐘前’
3、如果大于1小時小于24小時,顯示‘xx小時前’
4、如果大于24小時小于30天,顯示‘xxx天前’
5、否則顯示具體時間: 如2018/6/30 14:45
index.html
{{ create_time|handle_time }}?
if和for語句
if語句
{% if score >= 90 %}<p>優秀</p> {% elif score >= 80 %}<p>良好</p> {% elif score >= 60 %}<p>及格</p> {% else %}<p>不及格</p> {% endif %}for語句
<!--普通的遍歷--> <url>{% for user in users %}<li> {{ user.name }} </li>{% endfor %} </ul><!--含else的for--> <url>{% for user in users %}<li> {{ user.name }} </li>{% else %}<li> user not found </li>{% endfor %} </ul><!--字典遍歷--> <ul>{% for key,value in users.items() %}<dt> {{ key }} </dt><dd> {{value}} <dd>{% endfor %} </ul>jinjia2中還包含以下變量,可以獲取當前遍歷的狀態
| 變量 | 描述 |
| loop.index | 當前迭代的索引(從1開始) |
| loop.index0 | 當前迭代的索引(從0開始) |
| loop.first | 是否是第一次迭代,返回True或False |
| loop.last | 是否是最后一次迭代,返回True或False |
| loop.length | 序列的長度 |
注意:不可以使用continue和break表達式來控制循環的執行
?
宏
模板中的宏跟Python中的函數類似,可以傳遞參數,但是不能有返回值,可以將一些經常用到的代碼片段放到宏中,然后把一些不固定的值抽取出來當成一個變量
index.html
<!--定義宏--> {% macro input(name, value='', type='text') %}<input name="{{ name }}" value="{{ value }}" type="{{ type }}" /> {% endmacro %}<!--使用宏--> 用戶名: {{ input('username') }} <br /> 密碼: {{ input('password', type='password') }}上面我們把宏定義在模板文件index.html里面,但是在實際開發當中我們會把它單獨放到一個文件中
我們可以在templates下面創建一個目錄macros,在macros目錄下面創建文件macros.html文件,這個文件來寫宏
然后我們在index.html中如要使用宏就需要導入
{% from 'macros/macros.html' import input %} 用戶名: {{ input('username') }} <br /> 密碼: {{ input('password', type='password') }}或者這樣
{% import 'macros/macros.html' as macros %} 用戶名: {{ macros.input('username') }} <br /> 密碼: {{ macros.input('password', type='password') }}還有一個問題就是:宏文件里面能夠直接獲取到服務器傳遞過來的值嗎?
@app.route('/') def index():context = {'str1': 'hello'}return render_template('index.html', **context)macros/macros.html
{% macro input(name, value='', type='text') %}<input name="{{ name }}" value="{{ str1 }}" type="{{ type }}" /> {% endmacro %很顯然并沒有獲取到,如果我們想模板文件中能夠獲取到,需要在導入模塊的時候這樣寫:
{% import 'macros/macros.html' as macros with context%} 用戶名: {{ macros.input('username') }} <br /> 密碼: {{ macros.input('password', type='password') }}?
set和with定義模板變量
在模板中也可以定義變量
set
使用set定義變量,后面開始就可以引用此變量
index.html
{% set name = 'heboan' %} <h1>{{ name }}</h1>with
使用with定義變量,只能在with代碼塊里面才能引用
index.html
{% with name = 'heboan' %}<h1>{{ name }}</h1> {% endwith %}我們也可以把set包含在with里面,這樣的話set定義的變量也只能在with代碼塊里面生效
{% with name = 'heboan' %}{% set age = 18 %}<h1>{{ name }}</h1> <h2>{{ age }}</h2> {% endwith %}?
加載靜態文件
建好flask項目后,和templates一樣 ,flask自動為我們建立了一個目錄static,這個目錄是用來存放靜態文件的,比如css、js、圖片等。
當然,靜態文件目錄的位置也是可以修改的
按住ctrl點擊 app = Flask(__name__)中的Flask,可以看到默認有一個參數是static_folder='static'
如果我們想改的話,可以這樣
app = Flask(__name__, static_floder='<path>')這里,我以圖片來說明如何加載靜態文件,至于css、js都是一樣的操作
主要還是用到url_for()
我們現在static下創建以個目錄images,然后在該目錄存放一張圖片mm.jpg
index.html
<img src="{{ url_for('static', filename='images/mm.jpg') }}">?
include
include的作用就是在一個模板中可以包含其他額模板
比如一個頁面,頂部和底部是一樣的,只有中間的板塊不一樣,這樣的話,我們就可以創建2個公共的模板。然后在其他的模板中把他們include進來即可
在templates創建一個目錄common,在common創建兩個模板header.html和footer.html
header.html
<div><p>這是頭部</p> </div>footer.html
<div><p>這是底部</p> </div>在index.html中include
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body>{% include 'common/header.html' %}<div><p>---這是中間的內容---</p></div>{% include 'common/footer.html' %}</body> </html>?
模板繼承
前面我們使用了include把其他模板的內容包含進來,從而減少代碼量。然而這并不是最好的方案。我們還可以使用模板繼承
我們在templates目錄下創建一個模板文件base.html
我們在模板里面把會變動的地方使用{% block <name> %} {% endblock %}并取一個名字就可以了
然后我們在indext.html來繼承base.html
現在訪問首頁
轉載于:https://www.cnblogs.com/sellsa/p/9244723.html
總結
以上是生活随笔為你收集整理的7、Flask实战第7天:Jinjia2模板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BufferedInputStream
- 下一篇: 写一个判断素数的函数,在主函数输入一个整