根據 "settings.DevelopmentConfig" 這個字符串形式的路徑能夠導入 "settings" 這個模塊,而且能夠找到模塊中的 "DevelopmentConfig" 這個類,還能夠根據 "dir" 找到 "DevelopmentConfig" 類中的大寫的靜態字段html
import importlib path = "settings.DevelopmentConfig" p, c = path.rsplit('.', maxsplit=1) m = importlib.import_module(p) cls = getattr(m, c) # 如何根據cls這個類獲取到類中的靜態字段 for key in dir(cls): if key.isupper(): print(key, getattr(cls, key))
settings.py
配置文件python
import datetime class Config(object): TESTING = False PROPAGATE_EXCEPTIONS = None PRESERVE_CONTEXT_ON_EXCEPTION = None SECRET_KEY = None PERMANENT_SESSION_LIFETIME = datetime.timedelta(days=31) USE_X_SENDFILE = False SERVER_NAME = None APPLICATION_ROOT = '/' SESSION_COOKIE_NAME = 'session' SESSION_COOKIE_DOMAIN = None SESSION_COOKIE_PATH = None SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SECURE = False SESSION_COOKIE_SAMESITE = None SESSION_REFRESH_EACH_REQUEST = True MAX_CONTENT_LENGTH = None SEND_FILE_MAX_AGE_DEFAULT = datetime.timedelta(seconds=43200) TRAP_BAD_REQUEST_ERRORS = None TRAP_HTTP_EXCEPTIONS = False EXPLAIN_TEMPLATE_LOADING = False PREFERRED_URL_SCHEME = 'http' JSON_AS_ASCII = True JSON_SORT_KEYS = True JSONIFY_PRETTYPRINT_REGULAR = False JSONIFY_MIMETYPE = 'application/json' TEMPLATES_AUTO_RELOAD = None MAX_COOKIE_SIZE = 4093 class ProductionConfig(Config): DEBUG = False class DevelopmentConfig(Config): DEBUG = True
app.py
中能夠使用按需修改後的 settings.py
中的配置信息數據庫
from flask import Flask app = Flask(__name__) app.config.from_object("settings.DevelopmentConfig")
flask 中的路由url是依據帶參數的裝飾器寫的django
/<int:nid>
動態接收 id 值(int類型),能夠傳參/<nid>
未定義類型則默認接收 string 字符串類型from flask import Flask from flask import url_for @app.route('/index/<int:nid>', methods=["GET", "POST"], endpoint="n1") # endpoint="n1" 至關於 django 路由系統 url 中的 name 起別名進行反向解析 # 若是不寫 endpoint="..." 則默認爲:url_for("index") 視圖函數名稱 index # flask 路由反向解析用的是 url_for("n1") # 動態路由 # '/<int:nid>' 動態接收 id 值(int類型),能夠傳參 # '/<nid>' 未定義類型則默認接收 string 字符串類型 def index(nid): print(url_for("n1", nid=1)) # /index/1 return "Index"
import functools from flask import Flask from flask import render_template from flask import request from flask import redirect from flask import session from flask import url_for from flask import Markup from flask import flash from flask import get_flashed_messages app = Flask(__name__) app.config.from_object("settings.DevelopmentConfig") # 模擬數據庫中存儲的用戶 STUDENT_DICT = { 1: {'name': '小明', 'age': 18, 'gender': '男'}, 2: {'name': '小李', 'age': 19, 'gender': '男'}, 3: {'name': '小花', 'age': 17, 'gender': '女'}, } # def auth(func): # # '@functools.wraps(func)' 加上這個裝飾器,能夠避免被裝飾的函數名變爲'inner' # @functools.wraps(func) # def inner(*args, **kwargs): # if not session.get('user'): # return redirect(url_for('login')) # ret = func(*args, **kwargs) # return ret # return inner # 被'@app.before_request' 此裝飾器裝飾的業務邏輯會在全部視圖函數執行以前執行 # 跟 'django' 的 'process_request' 極爲類似 # 當被此裝飾器裝飾的業務邏輯有返回值時,整個flask框架中的全部視圖函數都不會被執行 # 直接顯示 "被此裝飾器裝飾的業務邏輯的返回值" @app.before_request def auth(): if request.path == '/login': return None if session.get('user'): return None return redirect(url_for('login')) # 被此全局模板函數裝飾器所裝飾的業務邏輯,不須要藉助任何視圖函數傳遞此方法給模板, # 此方法會自動傳遞到須要應用此方法的模板中! # 模板只須要調用便可 {{global_template_func(1, 2)}} 便可在頁面相應的位置顯示出 3 @app.template_global() def global_template_func(a, b): return a + b # {{ 1|filter_template_func(2, 3) }} # 頁面顯示 6 @app.template_filter() def filter_template_func(a, b, c): return a + b + c @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': user = request.form.get('user') password = request.form.get('password') if user == 'aliang' and password == '007': session['user'] = user return redirect(url_for('index')) return render_template('login.html', error='用戶名或密碼錯誤!') return render_template('login.html') @app.route('/index') # @auth def index(): return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') # @auth def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') # @auth def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info) def func(arg): return arg + 1 @app.route('/tpl') def tpl(): context = { 'users': ['小明', '小李', '小花'], # 'txt': "<input type='text' />", 'txt': Markup("<input type='text' />"), 'func': func } return render_template('tpl.html', **context) @app.route('/page1') def page1(): flash('存儲臨時數據') return "Session" @app.route('/page2') def page2(): flash_msg = get_flashed_messages() return flash_msg class Middleware(object): def __init__(self, origin_wsgi_app): self.origin_wsgi_app = origin_wsgi_app def __call__(self, *args, **kwargs): # 在請求以前作相應的業務邏輯 ret = self.origin_wsgi_app(*args, **kwargs) # 在請求以後作相應的業務邏輯 return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run()
request.method requestd.args request.form request.values requesdt.cookies request.headers request.path request.full_path request.script_root request.url request.base_url request.url_root request.host_url request.host request.files obj = request.files['the_file_name'] obj.save('/var/www/uploads/' + secure_filename(f.filename))
from flask import render_template from flask import redirect from flask import jsonify # 如下4種返回的數據都是請求體,能不能將請求頭也返回?能夠封裝! dic = {'k1': 'v1'} # return json.dumps(dic) # 至關於"django"中的JsonResponse return jsonify(dic) return "Index" return render_template("index.html") return redirect("/index")
定製返回的響應頭json
from flask import make_response # 將要返回的字符串"Index"封裝到"make_response"中 # 設置了響應體 obj = make_response("Index") # 設置了響應頭 obj.headers['xxxx'] = 'oooo' # 設置cookie信息 obj.set_cookie('key', 'value') return obj
flask 模板渲染語法跟python語法極其類似flask
# app.py 文件中 from flask import Markup def func(arg): return arg + 1 @app.route('/tpl') def tpl(): context = { 'users': ['小明', '小李', '小花'], # 'txt': "<input type='text' />", 'txt': Markup("<input type='text' />"), 'func': func } return render_template('tpl.html', **context)
tpl.html 模板文件中瀏覽器
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{users.0}} {{users[0]}} {{txt}} {{txt|safe}} {{func(6)}} </body> </html>
被此全局模板函數裝飾器所裝飾的業務邏輯,不須要藉助任何視圖函數傳遞此方法給模板,
此方法會自動傳遞到須要應用此方法的模板中!cookie模板只須要調用便可 {{global_template_func(1, 2)}} 便可在頁面相應的位置顯示出 3session
# app.py 文件中 @app.template_global() def global_template_func(a, b): return (a + b)
tpl.html 模板文件中app
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{global_template_func(1, 2)}} </body> </html>
在模板中這樣調用:{{ 1|filter_template_func(2, 3) }}
則在頁面相應位置顯示 6
# app.py 文件中 @app.template_filter() def filter_template_func(a, b, c): return a + b + c
tpl.html 模板文件中
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{1|filter_template_func(2, 3)}} {% if 1|filter_template_func(2, 3) %} <div>返回值爲6</div> {% else %} <div>沒有返回值</div> {% endif %} </body> </html>
layout.html 模板文件中
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% block content%} {% endblock %} </body> </html>
tpl.html 繼承 layout.html 模板文件
{% extends "layout.html"%} {% block content%} {{users.0}} {{users[0]}} {{txt}} {{txt|safe}} {{func(6)}} {% endblock %}
nav.html 模板插件——>導航欄等插件
......
tpl.html 文件中
{% extends "layout.html"%} {% block content%} {% include "nav.html" %} {{users.0}} {{users[0]}} {{txt}} {{txt|safe}} {{func(6)}} {% endblock %}
適用於某個標籤在整個頁面上屢次使用,能夠按照宏定義的方式將此標籤訂義爲一個代碼塊,在須要使用時直接調用便可!就不須要重寫不少遍了!
模板宏定義的意思是能夠在模板中定義一個代碼塊,代碼塊中能夠按照python函數的定義方式去定義某個須要在特定時刻使用的標籤
在須要顯示此標籤時,直接調用便可
以下:
{% macro tag(name, type='text', value='') %} <h1>宏定義input標籤</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交"> {% endmacro %} {{tag("user")}}
django 中的session信息放在數據庫中
flask 中的session信息通過加密以後保存在用戶瀏覽器的cookie中
能夠作權限管理
方法一:每一個須要登陸後才能夠訪問的頁面所對應的視圖函數中都查詢一次是否有session信息
方法二:利用裝飾器,在每一個須要登陸後才能夠訪問的頁面所對應的視圖函數上加裝飾器,在走相應的視圖函數以前先走裝飾器中定義好的判斷是否存在session信息的業務邏輯
裝飾器(應用於被裝飾的視圖函數較少時)
import functools def auth(func): @functools.wraps(func) # 加上這個裝飾器,能夠避免被裝飾的函數名變爲'inner' def inner(*args, **kwargs): if not session.get('user'): return redirect(url_for('login')) ret = func(*args, **kwargs) return ret return inner
方法三:使用 '@app.before_request' 裝飾器
被'@app.before_request' 此裝飾器裝飾的業務邏輯會在全部視圖函數執行以前執行,跟 'django' 的 'process_request' 極爲類似
當被此裝飾器裝飾的業務邏輯有返回值時,整個flask框架中的全部視圖函數都不會被執行,但全部被 '@app.after_request' 裝飾器裝飾的業務邏輯都會按照定義好的順序倒序執行後直接顯示 "被此裝飾器裝飾的業務邏輯的返回值"
當被此裝飾器裝飾的業務邏輯中返回 None 時,其餘的視圖才能正常執行
@app.before_request def auth(): if request.path == '/login': return None if session.get('user'): return None return redirect(url_for('login'))
原理:在session中存儲一個數據,讀取一次以後,經過pop將數據移除,能夠達到存一次取一次即失效的效果!
flask中的session 信息是通過加密後保存在cookie中的,能夠一直取,只要不過時,不手動刪除,則session信息一直存在!
藉助 flash
存儲某一臨時數據 & get_flashed_messages
獲取臨時數據,取一次即失效
from flask import flash from flask import get_flashed_messages @app.route('/page1') def page1(): flash('存儲臨時數據') return "Session" @app.route('/page2') def page2(): flash_msg = get_flashed_messages() return flash_msg # ['存儲臨時數據']
from flask import flash from flask import get_flashed_messages @app.route('/page1') def page1(): flash('存儲臨時數據1', '類別1') flash('存儲臨時數據2', '類別1') flash('存儲臨時數據3', '類別2') return "Session" @app.route('/page2') def page2(): flash_msg = get_flashed_messages(category_filter=['類別1']) return flash_msg # ['存儲臨時數據1', '存儲臨時數據2']
跟django的中間件的實現有較大區別
flask 項目啓動接口
if __name__ == '__main__': app.run()執行 run 方法後使得服務端處於監聽狀態
當有請求鏈接時,
try: run_simple(host, port, self, **options)
run_simple(host, port, self, **options)
中的第三個參數self()
即 flask 的實例化對象app()
會執行類的__call__
方法def __call__(self, environ, start_response): """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response)即在客戶端請求鏈接時,基於flask框架的項目服務端會執行
__call__
方法而咱們知道中間件的做用就是在請求經過wsgi封裝後通過路由匹配執行相應的視圖函數再返回相應的模板頁面以前作相應的業務邏輯,好比:發送某一請求訪問特定的頁面須要先登陸以後才能夠正常訪問。
因此,flask 框架中的中間件即在
__call__
方法執行以前作相關定義
flask 框架中的中間件即在
Flask
類的__call__
方法執行以前作相關定義
class Middleware(object): def __init__(self, origin_wsgi_app): self.origin_wsgi_app = origin_wsgi_app def __call__(self, *args, **kwargs): # 在請求以前作相應的業務邏輯 ret = self.origin_wsgi_app(*args, **kwargs) # 在請求以後作相應的業務邏輯 return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run()
類比於django的中間件
被'@app.before_first_request' 此裝飾器裝飾的業務邏輯會在 '@app.before_request' 裝飾的業務邏輯以前僅執行一次
@app.before_first_request def excute_first(): print("項目啓動以後第一次請求到來時,會在@app.before_request裝飾的業務邏輯以前僅僅執行一次")
被'@app.before_request' 此裝飾器裝飾的業務邏輯會在全部視圖函數執行以前執行,
跟 'django' 的 'process_request' 極爲類似
當被此裝飾器裝飾的業務邏輯有返回值時,整個flask框架中的全部視圖函數都不會被執行,但全部被 '@app.after_request' 裝飾器裝飾的業務邏輯都會按照定義順序倒序執行後直接顯示 "被此裝飾器裝飾的業務邏輯的返回值"
當被此裝飾器裝飾的業務邏輯沒有返回值即返回 None 時,請求按流程正常執行!
@app.before_request def auth(): print('請先登陸!')
被'@app.after_request' 此裝飾器裝飾的業務邏輯會在全部視圖函數執行以後執行跟 'django' 的 'process_response' 極爲類似
被裝飾的業務邏輯必需要有返回值,若沒有返回值,程序會報錯
@app.after_request def after(response): print('請求已經獲得響應!') return response
被此全局模板函數裝飾器所裝飾的業務邏輯,不須要藉助任何視圖函數傳遞此方法給模板,此方法會自動傳遞到須要應用此方法的模板中!
模板只須要調用便可 {{global_template_func(1, 2)}} 便可在頁面相應的位置顯示出 3
# app.py 文件中 @app.template_global() def global_template_func(a, b): return (a + b)
tpl.html 模板文件中
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{global_template_func(1, 2)}} </body> </html>
在模板中這樣調用:{{ 1|filter_template_func(2, 3) }}
則在頁面相應位置顯示 6
# app.py 文件中 @app.template_filter() def filter_template_func(a, b, c): return a + b + c
tpl.html 模板文件中
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{1|filter_template_func(2, 3)}} {% if 1|filter_template_func(2, 3) %} <div>返回值爲6</div> {% else %} <div>沒有返回值</div> {% endif %} </body> </html>
被'@app.errorhandler(404)' 此裝飾器裝飾的業務邏輯能夠自定義訪問出錯後的錯誤信息展現
@app.errorhandler(404) def not_found(error_msg): print(error_msg) return "訪問的頁面不存在!"