重定向,顧名思義,就是從新定向到一個新的位置,好比咱們在瀏覽器的頁面自動跳轉到了另外一個頁面,又好比訪問了一個頁面,而後觀察網址以後並非咱們輸入的網址,這個過程就是重定向完成的。javascript
http狀態碼 | 應用場景 | 優點 | |
---|---|---|---|
暫時性重定向 | 302 | 訪問一些須要權限的頁面,會自動重定向到權限認證的頁面 | 重定向在設計上會提高用戶體驗 |
永久性重定向 | 301 | 廢棄原有的網址被訪問,會自動重定向到新的網址確保用戶訪問成功 | 重定向在設計上會提高用戶體驗,有利於搜索引擎優化 |
例1:訪問淘寶的時候,你選擇了已經購買的商品,可是你並無登陸過淘寶,那麼這個時候若是隻是提示 「請登陸再訪問!」,那麼相信這種設計是留不住用戶的,不如直接爲用戶重定向到登陸頁面。css
例2:好比想廢棄本來的網址,那麼用戶並不知道這個事情,因此用戶仍是會訪問原來的網址,那麼就會內部作一個重定向到新啓用的網址,重定向的過程會有狀態碼的返回,搜索引擎捕捉到重定向的代碼,有利於搜索引擎優化。html
關鍵詞:重定向在設計上會提高用戶體驗 ,有利於搜索引擎優化前端
首先從flask
模塊中把導入redirect
java
from flask import Flask,redirect
from flask import Flask,redirect ... @app.route('/user_info/') def user_info(): name = request.args.get('name') pwd = request.args.get('pwd') if name=='mark' and pwd == '123': return '{}的信息'.format(name) return redirect('/login/') # 能夠換成 return redirect(url_for('login')) @app.route('/login/') def login(): return '這是登陸頁面' ...
沒有經過權限驗證的狀況python
經過權限驗證的狀況程序員
關鍵詞:暫時性重定向return redirect('/login/')
便可實現重定向flask
from flask import Flask,redirect ... @app.route('/user_info/') def user_info(): name = request.args.get('name') pwd = request.args.get('pwd') if name=='mark' and pwd == '123': return '{}的信息'.format(name) return redirect('/login/', code=301) # 會返回301狀態碼給瀏覽器 @app.route('/login/') def login(): return '這是登陸頁面' ...
關鍵詞:永久性重定向只給redirect('/login/', code=301)
多加了個code=301
參數bootstrap
實現視圖的業務邏輯和返回給前端的頁面邏輯分離的工具,咱們稱之爲模板引擎。瀏覽器
什麼是模板?
模板能夠理解爲一個特殊的html
文件,特殊之處就在於這個html
文件包含固定內容和動態部分,其動態部分能夠藉助模板引擎進行傳參
在上一章其實咱們已經應用過模板引擎,試想一下若是沒有模板引擎,直接給把模板的html代碼寫在視圖函數裏面,會給程序員的平常開發帶來了多大的困擾,模板引擎幫咱們分開了業務邏輯和頁面邏輯,而且咱們每次修改一個大字符串會很是不方便。模板引擎還能夠讀取並執行模板中的特殊語法標記,並根據傳入的數據將變量替換爲實際值,而後返回給瀏覽器,這個過程咱們稱之爲渲染。
關鍵字:完成了業務邏輯和頁面邏輯的分離,實現了動態的去渲染頁面。
Flask
如何使用模板引擎?Flask
使用jinja2
做爲框架的默認模板引擎,Jinja2
是基於python
的模板引擎,功能比較相似於於PHP
的smarty
,J2ee
的Freemarker
和velocity
。Jinja2
除了設置變量,還容許咱們在模板中添加if判斷,執行for迭代,調用函數等,以各類方式控制模板的輸出。而且jinja2
不限制模板的格式爲html
,能夠是任何格式的文本文件。
項目目錄
項目代碼
(1)login01.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陸界面</title> </head> <body> <h1>login01</h1> <!--login02.html文件的這一行的內容是:‘ <h1>login02</h1> ’ --> <form action="" method="POST"> 用戶:<input type="text" name="username"> 密碼:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html>
(2)login02.html
<meta charset="UTF-8"> <title>登陸界面</title> </head> <body> <h1>login01</h1> <!--login02.html文件的這一行的內容是:‘ <h1>login02</h1> ’ --> <form action="" method="POST"> 用戶:<input type="text" name="username"> 密碼:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html>
(3) server.py
from flask import Flask, render_template import config app = Flask(__name__) app.config.from_object(config) @app.route('/demo/') def demo(): return '<h2>手寫html</h2>' @app.route('/demo02/') def demo02(): return '''<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陸界面</title> </head> <body> <!--<form action="/login_request/" method="POST">--> <form action="" method="POST"> 用戶:<input type="text" name="username"> 密碼:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html>''' @app.route('/demo03/') def demo03(): return render_template('login01.html') @app.route('/demo04/') def demo04(): return render_template('box/login02.html') if __name__ == '__main__': app.run()
server.py代碼邏輯分析:
render_template('box/login02.html')
的路徑是templates文件夾的相對路徑Flask類中的template_folder
參數能夠指定模板尋找路徑
基於上2.3.1的項目
C:/Users/Administrator/Desktop/template_box
中,而且刪除項目中的templates的文件。app = Flask(__name__)
爲app = Flask(__name__,template_folder='C:/Users/Administrator/Desktop/template_box')
分析:
渲染一切正常 說明Flask類中的template_folder
參數能夠指定模板尋找路徑。
咱們以前提到過,模板引擎還能夠讀取並執行模板中的特殊語法標記,並根據傳入的數據將變量替換爲實際值,這個步驟咱們就稱之爲模板引擎傳參。
咱們傳參的時候要應用render_template()
利用render_template的第二個參數進行傳參,該函數在定義時候,第二個參數是可變長形參,因此在傳值的時候咱們能夠傳入多個關鍵字實參。
在模板中接收的時候使用{{}}
包裹參數進行接收。
目錄結構
Copy│ server.py │ └─templates # 文件夾 index.html
server.py
@app.route('/') def index(): return render_template('index.html',name="mark",age=18)
index.html
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板傳參</title> </head> <body> {{name}} {{age}} </body> </html>
目錄結構:同上
server.py
@app.route('/demo1/') def demo1(): context_dict = {"name":"mark", "age":"mark", "sex":"girl"} return render_template('index.html',context_dict = context_dict)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板傳參</title> </head> <body> {{context_dict.name}} {{context_dict.age}} {{context_dict.sex}} </body> </html>
目錄結構:同上
server.py
def demo2(): context_dict = {"name": "mark", "age": "mark", "sex": "girl", "other_info":{"tel":1365, "qq":565656}} return render_template('index.html',**context_dict)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板傳參</title> </head> <body> {{name}} {{age}} {{sex}} {{other_info.tel}} {{other_info["qq"]}} </body> </html>
在視圖函數中
在模板中
{{}}
包裹參數進行接收.
字典裏面的key取出value值。也能夠直接字典跟[]
進行取值。url_for()
在模板中若是有使用url的需求,咱們能夠直接手寫一個url,也可使用{{ url_for('視圖函數名') }
動態翻轉一個url。
項目目錄:
│ server.py │ └─templates # 文件夾 index.html info.html
server.py
... @app.route('/') def index(): return render_template('index.html', name="mark", age=18) @app.route('/info/') def info(): return render_template('info.html') ...
info.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>信息頁面</title> </head> <body> <h1>這是信息頁面</h1> </body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板傳參</title> </head> <body> <a href="/info/">正常跳轉</a> <a href="{{ url_for('info') }}">urlfor跳轉</a> </body> </html>
正常跳轉 和 urlfor跳轉,皆能夠實現跳轉到info.html頁面。
正常跳轉就不作演示了
在jinja2中用{% %}
特殊符號來編輯控制語句,一個語句以{% ... %}
爲起始 而且以{% end... %}
來標記結束。
可使用> , < , <=, ==,!=,
進行判斷,
也可使用 and,or,not,()
來進行邏輯合併
{% if age > 18 %} <p>成年人</p> {% elif age == 18 %} <p>剛剛成年</p> {% else %} <p>未成年</p> {% endif %}
注意:<p>
只是爲了渲染明顯
項目目錄:
│ server.py │ └─templates # 文件夾 index.html
server.py
... @app.route('/') def hello_world(): context_dict = { 'age': 17, 'sex': 'man', } return render_template('index.html',**context_dict) ...
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jinja2分支</title> </head> <body> {% if sex == 'man' %} <p>男人</p> {% else %} <p>女人</p> {% endif %} {% if age > 18 %} <p>成年人</p> {% elif age == 18 %} <p>剛剛成年</p> {% else %} <p>未成年</p> {% endif %} </body> </html>
for
循環能夠便利任何一個可迭代對象,包括列表、字典等,支持反向遍歷
列表循環:
{% for country in countrys%} <p>{{ country }}</p> {% else %} <p>沒有值</p> {% endfor %}
項目目錄:
│ server.py │ └─templates # 文件夾 index.html
sever.py
@app.route('/') def hello_world(): context_dict = { 'countrys':["1-china","2-America","3-French"] } return render_template('index.html',**context_dict)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>for循環</title> </head> <body> {% for country in countrys %} {# {% for country in countrys|reverse %} 能夠實現反向遍歷#} <p>{{ country }}</p> {% else %} <p>沒有值</p> {% endfor %} </body> </html>
反向遍歷實例
server.py`的 `{% for country in countrys %}` 改成 `{% for country in countrys|reverse %}
能夠實現反向遍歷,運行效果以下圖
項目目錄
│ server.py │ └─templates # 文件夾 index.html
sever.py
@app.route('/') def hello_world(): context_dict = { 'countrys':["1-china","2-America","3-French"] } return render_template('index.html',**context_dict) @app.route('/demo/') def demo(): context_dict ={ 'colleges':[ { 'name': '清華大學', 'area': '北京' }, { 'name': '復旦大學', 'area': '上海' '' }, { 'name': '吉林大學', 'area': '吉林' }, { 'name': '中山大學', 'area': '廣東' } ] } return render_template('index.html',**context_dict)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>for循環</title> </head> <body> <table> <tr> <th>1開始的序號</th> <th>0開始的序號</th> <th>大學名稱</th> <th>所屬地區</th> <th>總數</th> </tr> {% for college in colleges %} {% if loop.first %} <tr style="background: blue"> {% elif loop.last %} <tr style="background: yellow "> {% else %} <tr> {% endif %} <td>{{ loop.index }}</td> <td>{{ loop.index0 }}</td> <td>{{ college.name }}</td> <td>{{ college.area }}</td> <td>{{ loop.length }}</td> </tr> {% endfor %} </table> </body> </html>
for循環經常使用變量表
for循環經常使用變量 | 功能描述 |
---|---|
loop.index | 當前循環的索引(從1開始) |
loop.index0 | 當前循環的索引(從0開始) |
loop.first | 是不是第一次循環,是返回True,不然返回Flase |
loop.last | 是不是最後一次循環,是返回True,不然返回Flase |
loop.length | 總共能夠循環的次數 / 迭代器的長度 |
for還能夠else分支語法,若是for內部沒有遍歷出來內容,那麼就會走else分支,反之若是for循環遍歷出了內容,則不會運行else分支。
注意:jinja2
中的for
和 else
邏輯不通於python
在此不要類比python中的 for
和 else
。
{% for country in countrys|reverse %} <p>{{ country }}</p> {% else %} <p>沒有值</p> {% endfor %}
在模板中加載靜態文件的時候也要使用到url_for()
函數,去尋找具體的靜態文件資源。第一個參數是定位到static
文件夾,filename
參數定位到static文件夾內的具體資源。
{{ url_for('static',filename='相對於static文件夾的路徑') }}
項目目錄:
│ app.py │ ├─static # 文件夾 │ ├─css # 文件夾 │ │ demo.css │ │ │ ├─images # 文件夾 │ │ 1.png │ │ │ └─js # 文件夾 │ demo.js │ ├─templates # 文件夾 index.html
app.py
... @app.route('/') def hello_world(): return render_template('index.html') ...
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>靜態文件加載</title> <link rel="stylesheet" href="{{ url_for('static',filename='css/demo.css') }}"> <script src="{{ url_for('static',filename='js/demo.js') }}"></script> </head> <body> <img src="{{ url_for('static',filename='images/1.png') }}"> </body> </html>
demo.css
Copybody{ background: red; }
demo.js
Copyalert('hello world')
jinja2的模板繼承能夠把一些公共的代碼定義到一個基模板中,好比把導航欄、頁腳等通用內容放在基模板中,之後全部的子模板直接繼承基模板,在子模板被渲染時會自動包含繼承基模板的內容,經過模板的繼承能夠避免在多個模板中編寫重複的代碼。
在基模板中定義一些公共的代碼,子模板會繼承這些公共的代碼,可是子模板須要根據本身的需求去實現不一樣的代碼,這個時候就須要在基模板中提供一些接口,以便子模板實現本身的業務需求。
1 基本寫法
在基/父模板中定義接口(block)
{% block main %} {# main是自定義的變量名 #} {% endblock %}
在子模板中繼承父模板,而且重寫接口(block)
{% extends 'base.html' %} {# extends 後面跟的參數是導入的基模板相對於templates的路徑 #} {% block main %} {% endblock %}
2 子模板中調用父模板代碼block中的代碼
基模板中
{% block main %} <p>父模板中main中原有的內容</p> {% endblock %}
子模板中:
{% block main %} {{ super() }} {# 保留基模板中本塊的代碼 #} <p>子模板中重寫main的內容 </p> {% endblock %}
3 在子模板中調用其餘block中的代碼:
子模板中:
Copy{% block main %} {{ self.demo() }} {# self.其餘block名字 #} <p>子模板中重寫main的內容 </p> {% endblock %}
4 子模板中的想定義本身的代碼只能放到block中,不然無效
注意:這裏面咱們使用了bootstrap框架。
bootstrap3的中文官網:https://v3.bootcss.com/
1 首先下載 用於生產環境的 Bootstrap
2 解壓出來裏面的css文件
項目目錄
Copy│ app.py │ ├─static # 文件夾 │ └─css │ bootstrap-theme.css │ bootstrap-theme.css.map │ bootstrap-theme.min.css │ bootstrap-theme.min.css.map │ bootstrap.css │ bootstrap.css.map │ bootstrap.min.css │ bootstrap.min.css.map │ ├─templates # 文件夾 base.html detail.html
css文件夾: 是從咱們上面下載好的用於生產環境的 Bootstrap
中解壓出來的
base.html 注意:裏面的form
標籤中的內容和nav
標籤中的內容均是bootstrap框架的代碼截取,div
標籤是用於清除浮動
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父模板</title> <link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.css') }}"> </head> <body> <form class="navbar-form navbar-left" role="search"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <div style=" visibility:hidden;display:block;font-size:0;clear:both; height:50px"></div> {% block main %} <p>父模板中main中原有的內容</p> {% endblock %} <br> <br> <br> {% block demo %} <p>demo中原有的內容</p> {% endblock %} <div style=" visibility:hidden;display:block;font-size:0;clear:both; height:0"></div> <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li><a href="#">1</a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </body> </html>
detail.html
Copy{% extends 'base.html' %} {% block demo %} <p>子模板中重寫demo的內容</p> {% endblock %} {% block main %} {{ super() }} {# 保留基模板中本block的代碼 #} {{ self.demo() }} {# 調用demo block的代碼 #} <p>子模板中重寫main的內容 </p> {% endblock %}
app.py 注意:app.config.update(TEMPLATES_AUTO_RELOAD=True)
語句用於每次都從新加載模板文件
Copyfrom flask import Flask, render_template app = Flask(__name__) app.config.update(TEMPLATES_AUTO_RELOAD=True) @app.route('/') def hello_world(): return render_template('base.html') @app.route('/demo/') def demo(): return render_template('detail.html') if __name__ == '__main__': app.run()
子模板運行效果