模板基本語法html
{% if user %} {{ user }} {% else %} hello! <ul> {% for index in indexs %} <li> {{ index }} </li> {% endfor %} </ul>
一 變量前端
在模板中{{ variable }}結構表示變量,是一種特殊的佔位符,告訴模板引擎這個位置的值,從渲染模板時使用的數據中獲取;Jinja2除了能識別基本類型的變量,還能識別{};python
視圖:git
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/index")
def index():
data = {
"name": "test",
"size": 11,
"adict": {"title": "index"},
"alist": [1,2,3,4,5,6]
}
return render_template('index.html', **data)
# return render_template("index.html", name="tile")
if __name__ == '__main__':
app.run()
模板:web
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta http-equiv='Content-type' content='text/htm'> </head> <body> <p>name---{{ name }}</p> <p>size---{{ size }}</p> <p>adict---title:{{ adict["title"] }}</p> <p>adict---title:{{ adict.title }}</p> <p>alist---{{ alist }}</p> <p>alist---:alist[0]:{{ alist[0] }}</p> <p>alist---:alist[2]:{{ alist.2 }}</p> <p>alist---:alist[0]+alist[1]:{{ alist[0] + alist[1] }}</p> <p>{{ "hello" + "flask" }}</p> </body> </html>
自定義錯誤頁面:flask
@app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404
二 過濾器api
過濾器的本質就是函數。有時候咱們不單單只是須要輸出變量的值,咱們還須要修改變量的顯示,甚至格式化、運算等等,這就用到了過濾器。 過濾器的使用方式爲:變量名 | 過濾器。 過濾器名寫在變量名後面,中間用 | 分隔。如:{{variable | capitalize}},這個過濾器的做用:把變量variable的值的首字母轉換爲大寫,其餘字母轉換爲小寫。 其餘經常使用過濾器以下:服務器
2.1 字符串過濾器:cookie
safe:禁用轉義; <p>{{ '<em>hello</em>' | safe }}</p> capitalize:把變量值的首字母轉成大寫,其他字母轉小寫; <p>{{ 'hello' | capitalize }}</p> lower:把值轉成小寫; <p>{{ 'HELLO' | lower }}</p> upper:把值轉成大寫; <p>{{ 'hello' | upper }}</p> title:把值中的每一個單詞的首字母都轉成大寫; <p>{{ 'hello' | title }}</p> trim:把值的首尾空格去掉; <p>{{ ' hello world ' | trim }}</p> reverse:字符串反轉; <p>{{ 'olleh' | reverse }}</p> format:格式化輸出; <p>{{ '%s is %d' | format('name',17) }}</p> striptags:渲染以前把值中全部的HTML標籤都刪掉; <p>{{ '<em>hello</em>' | striptags }}</p>
2.2 支持鏈式使用過濾器session
<p>{{ 「 hello world 「 | trim | upper }}</p>
2.3 列表過濾器
first:取第一個元素 <p>{{ [1,2,3,4,5,6] | first }}</p> last:取最後一個元素 <p>{{ [1,2,3,4,5,6] | last }}</p> length:獲取列表長度 <p>{{ [1,2,3,4,5,6] | length }}</p> sum:列表求和 <p>{{ [1,2,3,4,5,6] | sum }}</p> sort:列表排序 <p>{{ [6,2,3,1,5,4] | sort }}</p>
2.4 語句塊過濾
{% filter upper %}
this is a Flask Jinja2 introduction
{% endfilter %}
2.5 自定義過濾器:
過濾器的本質是函數。當模板內置的過濾器不能知足需求,能夠自定義過濾器。自定義過濾器有兩種實現方式:一種是經過Flask應用對象的add_template_filter方法。還能夠經過裝飾器來實現自定義過濾器。
自定義的過濾器名稱若是和內置的過濾器重名,會覆蓋內置的過濾器。
實現方式一:經過調用應用程序實例的add_template_filter方法實現自定義過濾器。該方法第一個參數是函數名,第二個參數是自定義的過濾器名稱。
def list_step_2(li):
"""自定義過濾器"""
return li[::2]
# 註冊過濾器
app.add_template_filter(list_step_2, "li2")
實現方式二:用裝飾器來實現自定義過濾器。裝飾器傳入的參數是自定義的過濾器名稱。
@app.template_filter("li3")
def list_step_3(li):
"""自定義過濾器"""
return li[::3]
三 Web表單:
web表單是web應用程序的基本功能。
它是HTML頁面中負責數據採集的部件。表單有三個部分組成:表單標籤、表單域、表單按鈕。表單容許用戶輸入數據,負責HTML頁面數據採集,經過表單將用戶輸入的數據提交給服務器。
在Flask中,爲了處理web表單,咱們通常使用Flask-WTF擴展,它封裝了WTForms,而且它有驗證表單數據的功能。
WTForms支持的HTML標準字段
字段對象 | 說明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密碼文本字段 |
HiddenField | 隱藏文本字段 |
DateField | 文本字段,值爲datetime.date格式 |
DateTimeField | 文本字段,值爲datetime.datetime格式 |
IntegerField | 文本字段,值爲整數 |
DecimalField | 文本字段,值爲decimal.Decimal |
FloatField | 文本字段,值爲浮點數 |
BooleanField | 複選框,值爲True和False |
RadioField | 一組單選框 |
SelectField | 下拉列表 |
SelectMultipleField | 下拉列表,可選擇多個值 |
FileField | 文本上傳字段 |
SubmitField | 表單提交按鈕 |
FormField | 把表單做爲字段嵌入另外一個表單 |
FieldList | 一組指定類型的字段 |
WTForms經常使用驗證函數
驗證函數 | 說明 |
---|---|
DataRequired | 確保字段中有數據 |
EqualTo | 比較兩個字段的值,經常使用於比較兩次密碼輸入 |
Length | 驗證輸入的字符串長度 |
NumberRange | 驗證輸入的值在數字範圍內 |
URL | 驗證URL |
AnyOf | 驗證輸入值在可選列表中 |
NoneOf | 驗證輸入值不在可選列表中 |
使用Flask-WTF須要配置參數SECRET_KEY。
CSRF_ENABLED是爲了CSRF(跨站請求僞造)保護。 SECRET_KEY用來生成加密令牌,當CSRF激活的時候,該設置會根據設置的密匙生成加密令牌。
在HTML頁面中直接寫form表單:
#模板文件 <form method='post'> <input type="text" name="username" placeholder='Username'> <input type="password" name="password" placeholder='password'> <input type="submit"> </form>
視圖函數中獲取表單數據:
from flask import Flask,render_template,request
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print username,password
return render_template('login.html',method=request.method)
使用Flask-WTF實現表單。
pip install Flask-WTF
配置參數:
app.config['SECRET_KEY'] = '.........'
模板頁面:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta http-equiv='Content-type' content='text/htm'> </head> <body> <form method="post"> {{ reg_form.csrf_token }} {{ reg_form.username.label }} <p>{{ reg_form.username }}</p> {{ reg_form.username.errors.0 }} {{ reg_form.password.label }} <p>{{ reg_form.password }}</p> {{ reg_form.password.errors.0 }} {{ reg_form.repassword.label }} <p>{{ reg_form.repassword }}</p> {{ reg_form.repassword.errors.0 }} <br> {{ reg_form.submit }} </form> </body> </html>
視圖函數:
from flask import Flask, render_template, url_for, redirect, session from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, EqualTo app = Flask(__name__) app.config["SECRET_KEY"] = "ada898u2q11joloadad02" class RegiterForm(FlaskForm): username = StringField(label="用戶名", validators=[DataRequired("用戶名不能爲空")]) password = PasswordField(label="密碼", validators=[DataRequired("密碼不能爲空")]) repassword = PasswordField(label="確認密碼", validators=[DataRequired("確認密碼不能爲空"), EqualTo("password", "兩次密碼輸入不一致")]) submit = SubmitField(label="提交") @app.route("/register", methods=['GET', "POST"]) def register(): # 建立表單對象, 若是是post請求, 前端發送了數據,flask會把數據在構造form對象的數據,存在對象中 reg_form = RegiterForm() # 判斷form中的數據是否合法 if reg_form.validate_on_submit(): username = reg_form.username.data password = reg_form.password.data repassword = reg_form.repassword.data session["username"] = username print(username, password, repassword) return redirect(url_for("index")) return render_template('register.html', reg_form=reg_form) @app.route("/index") def index(): username = session.get("username") return "hello %s " % username if __name__ == '__main__': app.run()
四 控制語句
4.1 if控制語句
@app.route('/user') def user(): user = 'wusong' return render_template('user.html',user=user)
<html> <head> {% if user %} <title> hello {{user}} </title> {% else %} <title> welcome to flask </title> {% endif %} </head> <body> <h1>hello world</h1> </body> </html>
4.2 for循環語句
@app.route('/loop') def loop(): fruit = ['apple','orange','pear','grape'] return render_template('loop.html',fruit=fruit)
<html> <head> {% if user %} <title> hello {{user}} </title> {% else %} <title> welcome to flask </title> {% endif %} </head> <body> <h1>hello world</h1> <ul> {% for index in fruit %} <li>{{ index }}</li> {% endfor %} </ul> </body> </html>
五 宏、繼承、包含
相似於python中的函數,宏的做用就是在模板中重複利用代碼,避免代碼冗餘。
Jinja2支持宏,還能夠導入宏,須要在多處重複使用的模板代碼片斷能夠寫入單獨的文件,再包含在全部模板中,以免重複。
5.1 宏
定義宏
{% macro input() %} <input type="text" name="username" value=""> {% endmacro %}
調用宏
{{ input() }}
定義帶參數的宏
{% macro input1(name, value="", type="text") %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %}
調用宏,並傳遞參數
{{ input1(pwd, type="password") }}
把宏單獨抽取出來,封裝成html文件,其它模板中導入使用
文件名能夠自定義macro_input.html
{% macro function() %} <input type="text" name="username" placeholde="Username"> <input type="password" name="password" placeholde="Password"> <input type="submit"> {% endmacro %}
在其它模板文件中先導入,再調用
{% import 'macro_input.html' as func %} {{ func.function() }}
5.2模板繼承
模板繼承是爲了重用模板中的公共內容。通常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 %}
模板繼承使用時注意點:
不支持多繼承。
爲了便於閱讀,在子模板中使用extends時,儘可能寫在模板的第一行。
不能在一個模板文件中定義多個相同名字的block標籤。
當在頁面中使用多個block標籤時,建議給結束標籤起個名字,當多個block嵌套時,閱讀性更好。
5.3包含(Include)
Jinja2模板中,除了宏和繼承,還支持一種代碼重用的功能,叫包含(Include)。它的功能是將另外一個模板整個加載到當前模板中,並直接渲染。
示例:
include的使用
{% include 'hello.html' %}
包含在使用時,若是包含的模板文件不存在時,程序會拋出TemplateNotFound異常,能夠加上ignore missing關鍵字。若是包含的模板文件不存在,會忽略這條include語句。
示例:
include的使用加上關鍵字ignore missing
{% include 'hello.html' ignore missing %}
宏(Macro)、繼承(Block)、包含(include)均能實現代碼的複用。
繼承(Block)的本質是代碼替換,通常用來實現多個頁面中重複不變的區域。
宏(Macro)的功能相似函數,能夠傳入參數,須要定義、調用。
包含(include)是直接將目標模板文件整個渲染出來。
六 Flask中的特殊變量和方法
在Flask中,有一些特殊的變量和方法是能夠在模板文件中直接訪問的。
config 對象:
config 對象就是Flask的config對象,也就是 app.config 對象。
{{ config.SQLALCHEMY_DATABASE_URI }}
request 對象:
就是 Flask 中表示當前請求的 request 對象,request對象中保存了一次HTTP請求的一切信息。
request經常使用的屬性以下:
屬性 | 說明 | 類型 |
---|---|---|
data | 記錄請求的數據,並轉換爲字符串 | * |
form | 記錄請求中的表單數據 | MultiDict |
args | 記錄請求中的查詢參數 | MultiDict |
cookies | 記錄請求中的cookie信息 | Dict |
headers | 記錄請求中的報文頭 | EnvironHeaders |
method | 記錄請求使用的HTTP方法 | GET/POST |
url | 記錄請求的URL地址 | string |
files | 記錄請求上傳的文件 | * |
{{ request.url }}
url_for 方法:
url_for() 會返回傳入的路由函數對應的URL,所謂路由函數就是被 app.route() 路由裝飾器裝飾的函數。若是咱們定義的路由函數是帶有參數的,則能夠將這些參數做爲命名參數傳入。
{{ url_for('index') }} {{ url_for('post', post_id=1024) }}
get_flashed_messages方法:
返回以前在Flask中經過 flash() 傳入的信息列表。把字符串對象表示的消息加入到一個消息隊列中,而後經過調用 get_flashed_messages() 方法取出。
{% for message in get_flashed_messages() %} {{ message }} {% endfor %}
示例:
from flask import Flask, render_template, flash app = Flask(__name__) app.config["SECRET_KEY"] = "diaj29u912kjwsle01sda" flag = True @app.route("/index") def index(): global flag if flag: flash("flash1") flash("flash2") flash("flash3") flag = False return render_template("index.html") if __name__ == '__main__': app.run()
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta http-equiv='Content-type' content='text/htm'> </head> <body> <h1>閃現</h1> {% for msg in get_flashed_messages() %} {{ msg }} {% endfor %} </body> </html>