flask之二
預熱
- 在渲染模板的時候,默認會從項目根路徑下的
templates
目錄下查找模板 - 如果想要指定模板路徑的時候,就在初始化APP的時候,這樣操作即可:
app = Flask(__name__,template_folder='C:/templates') #template_folder可以指定模板位置
模板傳參
- 在使用
render_template
渲染模板的時候,可以傳遞關鍵字參數,以後直接在模板中使用就可以了 - 如果參數過多的話,那麼就可以將所有的參數放到一個字典中,然後再傳這個參數的時候使用
**
將字典打散成關鍵字參數。小例子:
- my_template.py
from flask import Flask,render_template app = Flask(__name__) app.debug = True @app.route('/') def hello_world(): context = { 'username': 'wanghui', 'age':19, 'children':{ 'user':'ccc', 'type':'stu', } } return render_template('index.html', **context) # return render_template('index.html',context=context) # return render_template('index.html',username='wanghui',age=19) if __name__ == '__main__': app.run()
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>my blog</title> </head> <body> <h1>這是模板渲染的數據</h1> {#<p>{{ username }}</p>#} {#<p>{{ age }}</p>#} {{ context.username }} {{ context.age }} <p>{{ username }}</p> <p>{{ children.user }}</p> </body> </html>
模板中的url_for
模板中的
url_for
和視圖函數中的url_for
是類似的,也是傳遞視圖函數的名字,也可以傳遞參數。使用的時候,需要在url_for
兩邊加上一個{{ url_for('func_name'),ref='/',id='1'}}
- templates.py
from flask import Flask,render_template,url_for app = Flask(__name__) app.debug = True @app.route('/') def hello_world(): return render_template('index.html') @app.route('/accounts/login/<id>/') def login(id): return render_template('login.html') if __name__ == '__main__': app.run(port=8888)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>my blog</title> </head> <body> <h1>這是從模板中渲染的</h1> <p><a href="{{ url_for('login',ref='/',id='1') }}">登陸</a></p> </body> </html>
- templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login page</title> </head> <body> <h1>這是登錄頁面</h1> {#{{ 用來存放變量 }}#} {#{% 用來執行函數或者邏輯代碼 %}#} </body> </html>
過濾器
有時候我們需要在模板中對一些變量進行處理,那麼就必須要類似於python中的函數一樣,可以將這個值傳到函數中,然後做一些操作。在模板中過濾器相當於是一個函數,把當前的變量傳入到過濾器中,然後過濾器會根據自己的功能,再返回相應的值,之後再將結果渲染到頁面上。
- 基本語法:
{{ variable |過濾器的名字 }}
guo - 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。
- format(value,*arags,**kwargs):格式化字符串。例如以下代碼:
{{ "%s" - "%s"|format('Hello?',"Foo!") }}\ 將輸出:Helloo? - Foo!
- 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):計算一個長字符串中單詞的個數。
- default過濾器詳解:
如果某個變量使用方式是{{ value|default('默認值')}}
,如果value這個key
不存在的話就使用過濾器提供的默認值;如果類似於python
中判斷一個值是否爲False(例如:空字典,空字符串,空列表的話)那麼久必須要傳遞另外一個參數{{ value | default('默認值',boolean=True)}}
;
可以使用or
來替換default('默認值',boolean=True)
(例如{{ siginature or '此人很懶沒有留下任何說明'}})
例子: - defaulte_falter.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def index(): context = { 'position':-9, 'signature':'', #'signature':'this ismy blog' } return render_template('index.html',**context) if __name__ == '__main__': app.run(debug=True)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> {#<p>個性簽名:{{ signature|default('此人很懶沒有留下任何說明!',boolean=True) }}</p>#} <p>個性簽名:{{ signature or '此人很懶沒有留下任何說明!'}}</p> </body> </html>
- esacape:轉義過濾器
safe
過濾器:可以關閉一公分字符串的自動轉義escape
過濾器:對某個字符串進行轉義autoescape
過濾器:可以對其代碼框內的代碼塊關閉自動轉義- first:返回序列中的第一個元素
- last:返回序列中的最後一個元素
- format:格式化輸出
- length:長度計算
- int:轉換成整數
- replase:舊字符串換成新的
truncate
:指定長度截取(結合striptags去除掉html字段之後截取純淨字符串然後按字數去做預覽頁填充)striptags
:去除標籤中的html字段- worldcount(s):統計一個長字符串中的單詞數
小例子: - escape.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def hello_world(): context = { 'position':-9, 'signature':'<script>alert("Hello world!")</script>', 'persons':['abc','def'], 'age':"18", 'article':'hello hello xxooo xxooo!!' } return render_template('index.html',**context) if __name__ == '__main__': app.run(debug=True,port=8080)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> {#{% autoescape off %}#} {#<p>個性簽名:{{ signature }}</p>#} {#{% endautoescape %}#} <p>{{ signature|safe }}</p> <p>{{ persons|first }}</p> <p>{{ persons[0] }}</p> <p>{{ persons|last }}</p> <p>{{ persons[-1] }}</p> <p>{{ "我的名字是%s"|format("hello word!") }}</p> <p>{{ "人數是 %d"|format(persons|length) }}</p> {% if age|int == 18 %} <p>年齡是18歲</p> {% else %} <p>年齡不是18歲</p> {% endif %} <p>{{ article|replace('hello','sssssz') }}</p> <p>{{ article|truncate(length=5) }}</p> <p>{{ signature|striptags }}</p> </body> </html>
自定義模板過濾器
- 在python文件中寫好自己的過濾器(本質上就是一個函數)
- 如果要在模板中調用這個過濾器,那就需要在這個函數上加一個裝飾器
@app.template_filter('過濾器名稱')
- 自動加載的話就在app下添加
app.config['TEMPLATES_AUTO_RELOAD'] = True
- 小例子:
- define_filter.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True @app.route('/') def hello_world(): context={ 'article':'anyway hello anyway hello abccc' } return render_template('index.html',**context) @app.template_filter('cut') def cut(value): vaule = value.replace("hello","sbsb") return value if __name__ == '__main__': app.run(debug=True,port=9090)**
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>myblog</title> </head> <body> <p>{{ article|cut }}</p> </body> </html>
實戰自定義過濾器
- 時間處理(從現在到發帖的時間差)
- shizhan.py
from flask import Flask,render_template from datetime import datetime app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True @app.route('/') def index(): context={ 'article':'aaa bbb ccc', 'create_time':datetime(2018,02,23,10,12,11) } return render_template('index.html',**context) @app.template_filter('handle_time') def handle_time(time): ''' 1.距離現在的時間多久,如果間隔在一分鐘以內就表示剛剛 2.在一小時以內就顯示xx分鐘前 3.在24小時以內就顯示xx小時前 4. 在一個月之內就顯示多少天之前 5. 否則就顯示具體的時間 :param time: :return: ''' if isinstance(time,datetime): now = datetime.now() timestamp = (now - time).total_seconds() #獲取間隔秒數 if timestamp < 60: return "剛剛" elif timestamp >=60 and timestamp<= 60*60: minutes = timestamp/60 return "%s分鐘前",int(minutes) elif timestamp >= 60*60 and timestamp <= 60*60*24: hours = timestamp/(60*60) return "%s小時前",int(hours) elif timestamp >= 60*60*24 and timestamp<= 60*60*24*30: days = timestamp/(60*60*24) return "%s天前",int(days) else: return time.strftime('%Y-%m-%d %H:%M') if __name__ == '__main__': app.run(port=9092,debug=True)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> <p>發表時間:{{ create_time|handle_time }}</p> </body> </html>
條件判斷
For循環
在
jinjia2
中的for
循環,跟python中的for循環基本是一致的,也是用for in形式;
而且可以便利所有的序列以及迭代器,但是唯一不同的是jinjia2
中的for
循環沒有break
和continue
- 小例子:
- for_ex.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def hello_world(): context = { 'users':['user01','user02','user03'], 'person':{ 'username':'wanghui', 'age':21, 'country':'china', }, 'books':[ { 'name':'sk1', 'author':'saa', 'price':100, }, { 'name': 'aaaeede1', 'author': 'se232aa', 'price': 103, }, { 'name': 'AAAew', 'author': 'VVVeqwea', 'price': 190, }, { 'name': 'skfdfds1', 'author': 'sdfsfsdfdaa', 'price': 30, } ] } return render_template('index.html',**context) if __name__ == '__main__': app.run(debug=True)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> <ul> {% for user in users %} <p>{{ user }}</p> {% endfor %} </ul> <table> <thead> <tr> <th>用戶名</th> <th>年齡</th> <th>國家</th> </tr> </thead> <tbody> <tr> {% for key,value in person.items() %} <td>{{ value }}</td> {% endfor %} </tr> </tbody> <table> <thead> <tr> <th>ID</th> <th>書名</th> <th>作者</th> <th>價格</th> <th>總數</th> </tr> </thead> <tbody> {% for book in books %} {% if loop.first %} <tr style="background: red"> {% elif loop.last %} <tr style="background: blue"> {% else %} <tr> {% endif %} <td>{{ loop.index }}</td> <td>{{ book.name }}</td> <td>{{ book.author }}</td> <td>{{ book.price }}</td> <td>{{ loop.length }}</td> </tr> {% endfor %} </tbody> </table> </table> <table border="1px"> <tbody> {% for x in range(1,10) %} <tr> {% for y in range(1,x+1) if y <= x %} <td>{{ y }}*{{ x }}={{ x*y }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </body> </html>
宏
模板中的宏跟python中的函數類似,可以傳遞參數,但是不能有返回值
使用宏的時候,參數可以是默認值 - 小例子:
- macro.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['DEBUG'] = True @app.route('/') def hello_world(): return render_template('index.html') if __name__ == '__main__': app.run(port=9999)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Macro</title> </head> <body> {% macro input(name="",value="",type="text") %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %} <h1>登陸頁面</h1> <table> <tbody> <tr> <td>用戶名:</td> <td>{{ input('username') }}</td> </tr> <tr> <td>密碼:</td> <td>{{ input('password',type='password') }}</td> </tr> <tr> <td></td> <td>{{ input(value='提交',type='submit') }}</td> </tr> </tbody> </table> </body> </html>
宏的導入
在真實的開發中,會將一些常用的宏單獨放在一個文件中,在需要使用的時候,再從這個文件中進行導入。
import語句的用法跟python中的import類似,可以直接import...as...,也可以from...import...或者from...import...as...,假設現在有一個文件,叫做forms.html,裏面有兩個宏分別爲input和textarea,如下:
注意事項:
a. inport
宏文件 as xxx
b. from 宏文件路徑 import 宏的名字 [as xxx]
c. 宏文件的路徑,不要以相對路徑去找,都要以templates
作爲絕對路徑去找
d. 如果想要在導入宏的時候,就把當前末班的一些參數傳遞給宏所在的模板,那麼就應該在導入的時候使用with context
- 小例子:
- macros.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['DEBUG'] = True @app.route('/') def hello_world(): return render_template('index/index.html') if __name__ == '__main__': app.run(port=9999)
- templates/macros/macros.html
{% macro input(name="",value="",type="text") %} <input type="{{ type }}" name="{{ name }}" value="{{ username }}"> {% endmacro %}
- templates/index/index.html
{#{% from "macros.html" import input as inp %}#} {% import "macros/macros.html" as macros with context %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Macro</title> </head> <body> <h1>登陸頁面</h1> <table> <tbody> <tr> <td>用戶名:</td> <td>{{ macros.input('username') }}</td> </tr> <tr> <td>密碼:</td> <td>{{ macros.input('password',type='password') }}</td> </tr> <tr> <td></td> <td>{{ macros.input(value='提交',type='submit') }}</td> </tr> </tbody> </table> </body> </html>
include標籤
- 這個標籤相當於是將指定模板中的代碼複製粘貼到當前的位置
include
標籤,如果要繼續使用父模板中的變量,直接用就可以了include
的路徑也和import一樣,需要從templates爲根,不要以相對路徑去找。
- 小例子:
- include_ex.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] @app.route('/') def hello_world(): return render_template('index.html',username='wanghui') @app.route('/detail/') def detail(): return render_template('course_detail.html') if __name__ == '__main__': app.run(debug=True)
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> {% include "common/header.html" %} <div class="content">中間的</div> {% include "common/footer.html" %} <ul>{{ username }}</ul> </body> </html>
- templates/course_detail.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include "common/header.html" %} <div class="content">文章詳情!</div> {% include "common/footer.html" %} </body> </html>
- templates/common/header.html
<style> .nav ul{ overflow: hidden; } .nav ul li{ float: left; margin: 0 20px; } </style> <nav class="nav"> <ul> <li>首頁</li> <li>博客詳情</li> <li>教程中心</li> <li>關於我</li> </ul> </nav>
- templates/common/footer.html
<footer>這是底部</footer>
set with語句
- 在模板中,可以使用
set
來定義變量;一旦定義了這個變量。那麼在後面的代碼中,都可以使用這個變量。 with
語句定義的變量,只能在with
的代碼塊中使用。超出with
代碼塊,則不能使用with
不一定要跟一個變量,也可以是一個空的with
語句,以後要用的話,就在with
中使用set
定義的變量來使用。
<body>
{% set username='wanghui' %}
<p>用戶名:{{ username }}</p>
{% with %}
{% set cla***oom='2018' %}
<p>班級:{{ cla***oom }}</p>
{% endwith %}
<p>別的班級{{ cla***oom }}</p>
</body>
加載靜態文件
- 加載靜態文件使用的是
url_for
函數,第一個參數爲static
,第二個參數是filename='path'
- 路徑查找要以
static
目錄作爲根目錄 - 小例子:
- static_ex.py
from flask import Flask,render_template app = Flask(__name__) app.config.update({ 'DEBUG':True, 'TEMPLATES_AUTO_RELOAD':True, }) @app.route('/') def hello_world(): return render_template('index.html') if __name__ == '__main__': app.run()
- static_ex.py
- static/css/index.css
body{ background: pink; }
- static/js/index.js
alert('hello user!')
- static/imgs/sas.jpg
圖片
- templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{{ url_for('static',filename="css/index.css") }}"> <script src="{{ url_for('static',filename="js/index.js") }}"></script> </head> <body> <img src="{{ url_for('static',filename='imgs/asa.jpg') }}" alt=""> </body> </html>
模板繼承
爲什麼需要模板繼承?
- 可以將一些公用的代碼單獨抽取出來放到一個父模板中,以後子模板直接繼承就給可以使用了。
- 這樣可以減少重複性的代碼,並且以後代碼修改起來也很方便
模板繼承的語法
- 使用
extends
語句來指明繼承的父模板。父模板的路徑也就是相對於templates
文件夾下的絕對路徑。例子如下{% extends 'base.html' %}
block語法
一般在父模板中只能定義一些共性公用的代碼,子模板可能要根據不同的需求實現不同的代碼。這時候父模板就應該提供一個接口,讓子模板來實現。從而實現業務的具體功能。
- 在父模板中
{% block body_block %} <p>我是base下的</p> {% endblock %}
- 在子模板中
{% block body_block %} <p>我是index的內容</p> {% endblock %}
調用父模板代碼block中的代碼
默認情況下,字幕版實現了父模板定義的block,那麼子模板中block的代碼就會覆蓋掉父模板中的代碼,要想保留父模板中的block的話就是用
{{ super() }}
來實現 - 父模板的內容:
{% block body_block %} <p style="background: red">base.html</p> {% endblock %}
- 子模板中的內容:
{% extends 'base.html' %} {% block body_block %} {{ super() }} <p style="background: green">我是index的內容</p> {% endblock %}
調用另外一個block中的代碼
在另外一個模板中使用其他模板中的代碼,可以使用
{{ self.blockname() }}
即可 - 父模板
<title>{% block title %} {% endblock %}</title> <body> {% block body_block %} <p style="background: red">base.html</p> {% endblock %} </body>
- 子模板:
{% extends 'base.html' %} {% block title %} MyIndex {% endblock %} {% block body_block %} {{ super() }} {{ self.title() }} <p style="background: green">我是index的內容</p> {% endblock %}
其他注意事項
- 繼承的代碼必須放在子模板中的第一行
{% extends 'base.html' %}
- 子模板中要實現自己的代碼,要放到block中,不然不生效
繼承的例子:
- inherit_ex.py
from flask import Flask,render_template app = Flask(__name__) app.config.update({ 'DEBUG':True, 'TEMPLATES_AUTO_RELOAD':True }) @app.route('/') def index(): return render_template('index.html') @app.route('/detail/') def detail(): return render_template('course_detail.html') if __name__ == '__main__': app.run()
- templates/base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %} {% endblock %}</title> <style> .nav ul{ overflow: hidden; } .nav ul li{ float: left; margin: 0 20px; } </style> </head> <body> <nav class="nav"> <ul> <li>首頁</li> <li>博客詳情</li> <li>教程中心</li> <li>關於我</li> </ul> </nav> {% block body_block %} <p style="background: red">base.html</p> {% endblock %} <footer>這是底部</footer> </body> </html>
- templates/index.html
{% extends 'base.html' %} {% block title %} MyIndex {% endblock %} {% block body_block %} {{ super() }} {{ self.title() }} <p style="background: green">我是index的內容</p> {% endblock %}
- templates/course_detail.html
{% extends 'base.html' %} {% block body_block %} <p>this is course </p> {% endblock %}