Flask中默認的模板語言是Jinja2html
from flask import Flask,render_template app = Flask(__name__) @app.route("/") def index(): content = { "name":"learning", "age":"18", "sex":"男" } return render_template("index.html",**content) if __name__ == "__main__": app.run(port=5225,debug=True)
index.html前端
<div> {{ name }} {{ age }} {{ sex }} </div>
效果django
# 常規作法,前端引入safejson
login.htmlflask
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ tags|safe }} </body> </html>
app.py後端
from flask import Flask,render_template app = Flask(__name__) @app.route("/") def index(): tags = "<input type='text' name='user' value='輸入'>" return render_template("login.html",tags=tags) if __name__ == "__main__": app.run(port=5225,debug=True)
# 引入Markup,它的做用在HTML的標籤上作一層封裝,讓Jinja2模板語言知道這是一個安全的HTML標籤緩存
login.html安全
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ tags }} </body> </html>
app.pycookie
from flask import Flask,render_template,Markup app = Flask(__name__) @app.route("/") def index(): tags = "<input type='text' name='user' value='輸入'>" markup = Markup(tags) return render_template("login.html",tags=markup) if __name__ == "__main__": app.run(port=5225,debug=True)
app.pysession
from flask import Flask,render_template,Markup app = Flask(__name__) # 定義一個函數 def sums(a,b): return a+b @app.route("/") def index(): return render_template("login.html",tags=sums) if __name__ == "__main__": app.run(port=5225,debug=True)
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ tags }} <div>{{ tags(38,37) }}</div> </body> </html>
效果:
from flask import Flask,request,redirect,render_template,session app = Flask(__name__) app.secret_key = "123" # 開啓session功能的時候必須添加該配置secret_key # 模擬數據 STUDENT_DICT = { 1: {'name': '呂洋'}, 2: {'name': '黃曉'}, 3: {'name': '餘燼'}, } @app.route("/login",methods=["GET","POST"]) def login(): if request.method =="GET": return render_template("login.html") if request.method == "POST": username = request.form.get("username") password = request.form.get("password") if username =="bob" and password == "123": session["user"] = username return redirect("/index") else: return render_template("login.html", msg="用戶名密碼錯誤") @app.route("/index") def index(): if session.get("user"): return render_template("index.html",stu=STUDENT_DICT) return redirect("/login") if __name__ == "__main__": app.run(port=5225,debug=True)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1px"> <tr> <th>id</th> <th>name</th> <th>option</th> </tr> <tr> {% for k,v in stu.items() %} <td>{{ k }}</td> <td>{{ v.name }}</td> <td><a href="/detail?id={{ k }}">詳細</a>|<a href="/delete/{{ k }}">刪除</a></td> </tr> {% endfor %} </table> </body> </html>
# 用戶必須先登陸,才能訪問index
效果:
說明:
html模板渲染通常都存放在項目主目錄下的templates下,不然會出現一個jinja2的異常
開啓session功能,這裏必需要添加secret_key,若是在實例化的app中沒有 secret_key 會拋異常
函數類:
@app.template_global()和@app.template_filter()
和django中的inclusion_tag以及filter很相似
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ sums(15,15) }} {{ 22|a_b_c_sum(15,15) }} </body> </html>
在模板中執行函數,須要先定義一個函數:
app.py
from flask import Flask,render_template,Markup app = Flask(__name__) @app.template_global() def sums(a,b): return a+b @app.template_filter() def a_b_c_sum(a, b, c): return a + b + c @app.route("/") def index(): return render_template("login.html",tags="") # 注意這裏也不同了 if __name__ == "__main__": app.run(port=5225,debug=True)
非函數類:
before_request 和 after_request
@before_first_request,註冊一個函數,在處理第一個請求以前執行。它和@before_request同樣,惟一區別是它只執行一次
@after_request 註冊一個函數,會在用戶請求獲得response響應以後,還未返回用戶以前執行,它能夠作統計訪問量來使用
@teardown——request 註冊一個函數,即便有未處理的異常拋出,也在每次請求以後運行
from flask import Flask,request,redirect,session app = Flask(__name__) app.secret_key = "fsdfs" @app.before_request def is_login(): # 判斷是否登陸 # 白名單設置,判斷爲登陸頁面時 if request.path == "/login": # 跳過處理 return None # 判斷session是不存在時 if not session.get("user"): # 重定向到登陸頁面 return redirect("/login") @app.route("/login") def login(): pass if __name__ == '__main__': app.run("0.0.0.0", 5000)
和django中的模板使用方式同樣
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Welcome to My</h1> <h2>下面的內容是不同的</h2> {% block content %} {% endblock %} </body> </html>
login.html
{% extends "index.html" %} {% block content %} <h4>歡迎登錄</h4> <form> 用戶名:<input type="text" name="user"> 密碼:<input type="text" name="pwd"> <input type="submit" value="提交"> </form> {% endblock %}
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Welcome to My</h1> {% include "login.html" %} </body> </html>
login.html
<form> 用戶名:<input type="text" name="user"> 密碼:<input type="text" name="pwd"> <input type="submit" value="提交"> </form>
經常使用的過濾器
abs # 絕對值 default # 若是當前變量沒有值,則會使用參數中的值來替代 escape # 轉義字符 first #返回一個序列的第一個元素 format #格式化字符串 last # 返回一個序列的最後一個元素 length # 返回一個序列的長度 join # 拼接字符串 safe # 關掉轉義 int # 轉爲int類型 float # 轉爲浮點類型 lower # 轉換爲小寫 upper # 轉換爲大寫 replace # 替換 truncate # 截取length長度的字符串 striptags # 刪除字符串中全部的html標籤,若是出現多個空格,將替換成一個空格
default過濾器的使用
他比較特別,使用必需要加上boolean=True
@app.route("/") def index(): content = { "direction":None } return render_template("index.html",**content)
index.html
<div> {{ direction|default("這是對default的使用說明",boolean=True) }} </div>
效果
from flask import Flask,request app = Flask(__name__) @app.route("/info", methods=["GET", "POST"]) def student_info(): stu_id = int(request.args["id"]) # 獲取前端url中的id值,注意格式類型 return f"如家{stu_id}號房" # Python3.6的新特性 f"{變量名}" if __name__ == "__main__": app.run(port=5225,debug=True)
效果:
反向url地址,默認爲視圖函數名 (url_for)
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", methods=["GET", "POST"],endpoint="r_info") def student_info(): print(url_for("r_info")) # /info stu_id = int(request.args["id"]) # 獲取前端url中的id值,注意是格式類型 return f"如家{stu_id}號房" # Python3.6的新特性 f"{變量名}" if __name__ == "__main__": app.run(port=5225,debug=True)
url欄輸入http://127.0.0.1:5225/info?id=2,會打印出如上代碼
用於反向生成url,也能夠附帶一些參數,好比想要完整的URL,能夠設置_external爲Ture
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", methods=["GET", "POST"],endpoint="r_info") def student_info(): print(url_for("r_info", _external=True)) # http://127.0.0.1:5225/info stu_id = int(request.args["id"]) # 獲取前端url中的id值,注意是格式類型 return f"如家{stu_id}號房" # Python3.6的新特性 f"{變量名}" if __name__ == "__main__": app.run(port=5225,debug=True)
# 這樣咱們獲取了完整路徑,可是參數還未獲取,能夠在後面再追加上咱們的id, url_for("r_info", _external=True,id=stu_id),這樣就能獲取完整url
對於url_for,咱們還能夠經過視圖函數解析出url
from flask import Flask,request,url_for app = Flask(__name__) @app.route('/') def hello_world(): return url_for('my_list',page=6) #url_for裏面:第一個是視圖函數,第二個是url須要的參數 @app.route('/list/<page>/') def my_list(page): return 'my_list' if __name__ == "__main__": app.run(port=5225,debug=True)
效果
url_for裏面多餘的參數會當作搜索字符
@app.route('/') def hello_world(): return url_for('my_list',page=2,count=2,age=18) @app.route('/list/<page>/') def my_list(page): return 'my_list'
效果
視圖函數的參數默認值{"nid":100}
url地址結尾符"/"的控制
False : 不管結尾 "/" 是否存在都可以訪問
True : 表示開啓路由嚴格匹配模式,結尾必須不能是 "/"
from flask import Flask app = Flask(__name__) @app.route("/info",strict_slashes=True) def student_info(): return "如家" if __name__ == "__main__": app.run(port=5225,debug=True)
# 爲True,路由末尾不能再加反斜槓,否則報錯
# 爲False,路由末尾對反斜槓不作嚴格要求
url地址重定向
from flask import Flask app = Flask(__name__) @app.route("/info",redirect_to="/bbb") def student_info(): return "如家" @app.route("/bbb") def bbb(): return "去你的"
# 輸入http://127.0.0.1:5225/info,它會自動發生跳轉,到http://127.0.0.1:5225/bbb
from flask import Flask,url_for app = Flask(__name__) @app.route("/info/<int:nid>",endpoint="r_info") def student_info(nid): print(url_for("r_info", _external=True, nid=nid)) return f"如家{nid}" if __name__ == "__main__": app.run(port=5230,debug=True)
效果:
@app.route('/user/<username>') # 不加參數的時候默認是字符串形式的 @app.route('/post/<int:post_id>') # 指定int,說明是整型的 @app.route('/post/<float:post_id>') @app.route('/post/<path:path>') @app.route('/login', methods=['GET', 'POST'])
對應關係
DEFAULT_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 接收多個路徑 'path': PathConverter, 和string相似,可是接收斜槓 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, }
對於any:
@app.route("/<any(blog,user):url_path>/<id>/") def index(url_path,id): if url_path == 'blog': return '博客詳情%s' % id else: return '用戶詳情%s' % id
效果
對於path
@app.route('/article/<path:test>/') def test_article(test): return 'test_article:{}'.format(test)
效果:
具體代碼演示
from flask import Flask from werkzeug.routing import BaseConverter # 自定義正則轉換器 class RegexConverter(BaseConverter): def __init__(self, url_map, *args): super(RegexConverter, self).__init__(url_map) # 將接受的第1個參數看成匹配規則進行保存 self.regex = args[0] app = Flask(__name__) # 將自定義轉換器添加到轉換器字典中,並指定轉換器使用時名字爲: re app.url_map.converters['re'] = RegexConverter @app.route('/user/<re("[0-9]{3}"):user_id>') def user_info(user_id): return "user_id 爲 %s" % user_id if __name__ == "__main__": app.run(debug=True)
效果
也能夠參考祥哥博客
開啓debug模式
from flask import Flask app = Flask(__name__) # type:Flask app.config["DEBUG"] = True if __name__ == '__main__': app.run()
config中的全部key值
{ 'DEBUG': False, # 是否開啓Debug模式 'TESTING': False, # 是否開啓測試模式 'PROPAGATE_EXCEPTIONS': None, # 異常傳播(是否在控制檯打印LOG) 當Debug或者testing開啓後,自動爲True 'PRESERVE_CONTEXT_ON_EXCEPTION': None, # 一兩句話說不清楚,通常不用它 'SECRET_KEY': None, # 以前遇到過,在啓用Session的時候,必定要有它 'PERMANENT_SESSION_LIFETIME': 31, # days , Session的生命週期(天)默認31天 'USE_X_SENDFILE': False, # 是否棄用 x_sendfile 'LOGGER_NAME': None, # 日誌記錄器的名稱 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, # 服務訪問域名 'APPLICATION_ROOT': None, # 項目的完整路徑 'SESSION_COOKIE_NAME': 'session', # 在cookies中存放session加密字符串的名字 'SESSION_COOKIE_DOMAIN': None, # 在哪一個域名下會產生session記錄在cookies中 'SESSION_COOKIE_PATH': None, # cookies的路徑 'SESSION_COOKIE_HTTPONLY': True, # 控制 cookie 是否應被設置 httponly 的標誌, 'SESSION_COOKIE_SECURE': False, # 控制 cookie 是否應被設置安全標誌 'SESSION_REFRESH_EACH_REQUEST': True, # 這個標誌控制永久會話如何刷新 'MAX_CONTENT_LENGTH': None, # 若是設置爲字節數, Flask 會拒絕內容長度大於此值的請求進入,並返回一個 413 狀態碼 'SEND_FILE_MAX_AGE_DEFAULT': 12, # hours 默認緩存控制的最大期限 'TRAP_BAD_REQUEST_ERRORS': False, # 若是這個值被設置爲 True ,Flask不會執行 HTTP 異常的錯誤處理,而是像對待其它異常同樣, # 經過異常棧讓它冒泡地拋出。這對於須要找出 HTTP 異常源頭的可怕調試情形是有用的。 'TRAP_HTTP_EXCEPTIONS': False, # Werkzeug 處理請求中的特定數據的內部數據結構會拋出一樣也是「錯誤的請求」異常的特殊的 key errors 。 # 一樣地,爲了保持一致,許多操做能夠顯式地拋出 BadRequest 異常。 # 由於在調試中,你但願準確地找出異常的緣由,這個設置用於在這些情形下調試。 # 若是這個值被設置爲 True ,你只會獲得常規的回溯。 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', # 生成URL的時候若是沒有可用的 URL 模式話將使用這個值 'JSON_AS_ASCII': True, # 默認狀況下 Flask 使用 ascii 編碼來序列化對象。若是這個值被設置爲 False , # Flask不會將其編碼爲 ASCII,而且按原樣輸出,返回它的 unicode 字符串。 # 好比 jsonfiy 會自動地採用 utf-8 來編碼它而後才進行傳輸。 'JSON_SORT_KEYS': True, #默認狀況下 Flask 按照 JSON 對象的鍵的順序來序來序列化它。 # 這樣作是爲了確保鍵的順序不會受到字典的哈希種子的影響,從而返回的值每次都是一致的,不會形成無用的額外 HTTP 緩存。 # 你能夠經過修改這個配置的值來覆蓋默認的操做。但這是不被推薦的作法由於這個默認的行爲可能會給你在性能的代價上帶來改善。 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, }
咱們能夠建立一個setting文件
class FlaskSetting(object): DEBUG = True
須要使用,直接導入就能夠
static_folder = 'static', # 靜態文件目錄的路徑 默認當前項目中的static目錄 static_host = None, # 遠程靜態文件所用的Host地址,默認爲空 static_url_path = None, # 靜態文件目錄的url路徑 默認不寫是與static_folder同名,遠程靜態文件時複用 # host_matching是否開啓host主機位匹配,是要與static_host一塊兒使用,若是配置了static_host, 則必須賦值爲True # 這裏要說明一下,@app.route("/",host="localhost:5000") 就必需要這樣寫 # host="localhost:5000" 若是主機頭不是 localhost:5000 則沒法經過當前的路由 host_matching = False, # 若是不是特別須要的話,慎用,不然全部的route 都須要host=""的參數 subdomain_matching = False, # 理論上來講是用來限制SERVER_NAME子域名的,可是目前尚未感受出來區別在哪裏 template_folder = 'templates' # template模板目錄, 默認當前項目中的 templates 目錄 instance_path = None, # 指向另外一個Flask實例的路徑 instance_relative_config = False # 是否加載另外一個實例的配置 root_path = None # 主模塊所在的目錄的絕對路徑,默認項目目錄
若是設置template_folder = 'templates',這裏面的templates它是相對路徑!
咱們在使用該模板時,應該這麼設置 template_folder = '../templates'
結構圖:
./
├── bin
│ └── app.py
├── static
│ └── learning.jpg
└── templates
└── login.html
案例:
from flask import Flask,render_template from flask_login import login_required # 第三方包,須要下載 app = Flask(__name__,template_folder="../templates") # 有時候會找不到,需加上template_folder @app.route("/") def login(): return render_template("login.html") @app.route("/log") @login_required # 不能直接訪問該路由 def index(): return render_template("index.html") if __name__ == "__main__": app.run(port=5230,debug=True)
靜態文件目錄的路徑 默認當前項目中的static目錄
結構圖
./
├── bin
│ └── app.py
├── static
│ └── learning.jpg
└── templates
└── login.html
app.py
from flask import Flask,render_template app = Flask(__name__,template_folder="../templates",static_folder="../static") @app.route("/") def index(): return render_template("login.html") if __name__ == "__main__": app.run(port=5230,debug=True)
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>頭像</h3> <img src="/static/learning.jpg" alt=""> </body> </html>
效果
from flask import Flask,render_template app = Flask(__name__,template_folder="../templates",static_folder="../static",static_url_path="/app") @app.route("/") def index(): print(app.static_folder) # C:\Users\Learning\Desktop\ffflask\bin\../static print(app.static_url_path) # /app return render_template("login.html") if __name__ == "__main__": app.run(port=5230,debug=True)
上面案例已經使用過session,這裏只強調一點,使用session必須配製secret_key,它是一段祕鑰字符串,本身隨意填寫
from flask import session app = Flask(__name__) app.secret_key = "ask"
通常session咱們能夠作登陸驗證使用