Flask是一個基於python依賴jinjia2模板和Werkzeug WSGI 服務的一個微型框架. werkzeug和Django中的wsgiref模塊同樣其本質就是一個socket服務端,,其用於接收http請求並對請求進行預處理,而後觸發Flask框架,開發人員基於Flask框架提供的功能對請求進行相應的處理,並返回給用戶,若是要返回給用戶複雜的內容時,須要藉助jinja2模板來實現對模板的處理,即:將模板和數據進行渲染,將渲染後的字符串返回給用戶瀏覽器。css
Werkzeug 並非 一個框架,它是一個 WSGI 工具集的庫,你能夠經過它來建立你本身的框架或 Web 應用html
Flask 的特色: 短小精悍,易於擴展第三方組件豐富.前端
Flask是一個微框架,python
微」(micro) 並不表示你須要把整個 Web 應用塞進單個 Python 文件(雖然確實能夠 ),也不意味着 Flask 在功能上有所欠缺。微框架中的「微」意味着 Flask 旨在保持核心簡單而易於擴展。Flask 不會替你作出太多決策——好比使用何種數據庫。而那些 Flask 所選擇的——好比使用何種模板引擎——則很容易替換。除此以外的一切都由可由你掌握。如此,Flask 能夠與您珠聯璧合。mysql
默認狀況下,Flask 不包含數據庫抽象層、表單驗證,或是其它任何已有多種庫能夠勝任的功能。然而,Flask 支持用擴展來給應用添加這些功能,如同是 Flask 自己實現的同樣。衆多的擴展提供了數據庫集成、表單驗證、上傳處理、各類各樣的開放認證技術等功能。Flask 也許是「微小」的,但它已準備好在需求繁雜的生產環境中投入使用。jquery
flask和djano的區別?web
djano大而全,無socket,藉助第三方模塊wsgiref模塊,內部提供: ORM admin 中間件,Form,ModelForm,session,緩存,信號CSRF
Flask ,短小精悍,易於擴展,無socket,藉助第三方庫Werkzeug.第三方組件豐富
flask官網https://flask.palletsprojects.com/en/1.1.x/ 1.1版本正則表達式
Flask的簡單應用sql
#一個基於werkzeug庫的Wsgi應用應該是這樣的 from werkzeug.wrappers import Request,Response from werkzeug.serving import run_simple @Request.application def hello(request): return Response('Hello,werkzeug') if __name__ == '__main__': run_simple('localhost',4000,hello)
Flask就是基於werkzeug來開發應用程序的數據庫
#簡單的Flask應用 hello from flask import Flask#導入Flask類 app=Flask(__name__)#實例化一個對象,這個對象就是咱們的W基於WSGI的應用程序,括號裏的參數是給對象起的名字,隨便一個字符串就能夠,__name__表示的是模塊名字的字符串 @app.route('/index') #router函數把url和視圖函數捆綁起來 def index(): return 'Hello Flask' if __name__ == '__main__': print(type(__name__)) app.run(debug=True)#至關於run_simple('localhost',5000,index),
方法一:app.run(),或者在命令行中運行該項目的啓動文件python xxx.py
方法二,在命令行中,啓動輸入flask run 就啓動了.Flask經過依賴包Click內置了一個命令行交互系統,當咱們按照flask後,會自動添加一個flask命令腳本,咱們能夠經過執行flask命令來執行該腳本.注意這個啓動文件必須是app.py才能夠用
雖然 run() 方法適用於啓動本地的開發服務器,可是你每次修改代碼後都要手動重啓它。這樣並不夠優雅,注意不能用在生產環境中.緣由爲:
#在服務上開啓調試模式會有很大的安全隱患,攻擊裝會經過你的調試信息來獲取你的數據庫結構.另外一方面調試頁面顯示的錯誤內容會讓咱們用戶很反感
在開發模式下flask會自動激活Wergzurg內置的調試器和重載器.
1.是debug=True使用了flask自帶的服務器,性能差,
2.這樣會把咱們的錯誤信息打印到前端,因此在生產環境中要刪除掉debug=True
有兩種方法來改變這個弊端
方法一: 直接在應用對象上設置
if __name__ == '__main__': app.debug=True app.run()#至關於run_simple('localhost',5000,index),
方法二: 在run函數中設置
app.run(debug=True)
flask中的配置文件是一個flask.config對象(繼承字典)
flask中的配置文件是一個flask.config.Config對象(繼承字典),默認配置爲: 2 { 3 'DEBUG': get_debug_flag(default=False), 是否開啓Debug模式 4 'TESTING': False, 是否開啓測試模式 5 'PROPAGATE_EXCEPTIONS': None, 6 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 7 'SECRET_KEY': None, 8 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), 9 'USE_X_SENDFILE': False, 10 'LOGGER_NAME': None, 11 'LOGGER_HANDLER_POLICY': 'always', 12 'SERVER_NAME': None, 13 'APPLICATION_ROOT': None, 14 'SESSION_COOKIE_NAME': 'session', 15 'SESSION_COOKIE_DOMAIN': None, 16 'SESSION_COOKIE_PATH': None, 17 'SESSION_COOKIE_HTTPONLY': True, 18 'SESSION_COOKIE_SECURE': False, 19 'SESSION_REFRESH_EACH_REQUEST': True, 20 'MAX_CONTENT_LENGTH': None, 21 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 22 'TRAP_BAD_REQUEST_ERRORS': False, 23 'TRAP_HTTP_EXCEPTIONS': False, 24 'EXPLAIN_TEMPLATE_LOADING': False, 25 'PREFERRED_URL_SCHEME': 'http', 26 'JSON_AS_ASCII': True, 27 'JSON_SORT_KEYS': True, 28 'JSONIFY_PRETTYPRINT_REGULAR': True, 29 'JSONIFY_MIMETYPE': 'application/json', 30 'TEMPLATES_AUTO_RELOAD': None, 31 }
若是咱們要更改配置文件的話用這種方法
settings.py
class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): """ 生產環境 """ DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): """ 開發環境 """ DEBUG = True class TestingConfig(Config): """ 測試環境 """ TESTING = True #PS: 從sys.path中已經存在路徑開始寫 #PS: settings.py文件默認路徑要放在程序root_path目錄,若是instance_relative_config爲True,則就是instance_path目錄
導入配置文件使用app.config.from_object(),注意這裏使用的是模塊的導入而不是路徑的導入
flask_demo.py
from flask import Flask app=Flask(__name__) app.config.from_object('seetings.DevelopmentConfig') #直接導入配置文件中的類就能夠了 @app.route('/index') def index(): return 'Hello Flask' if __name__ == '__main__': print(type(__name__)) app.run() flask_demo
使用配置文件中的數據
咱們知道flask中的app.comfig是一個字典對象,注意配置文件中的變量名要大寫,小寫不加載。源碼中規定的
因此配置文件有這麼幾種狀況
狀況一:配置文件爲這樣
#config.py DEBUG = TRUE
from flask import Flask app = Flask(__name__) app.config.from_object('config') # 這樣導入 def hello(): return 'hello' app.add_url_rule('/hello', view_func=hello) if __name__ == '__main__': app.run(debug=app.config['DEBUG'])
狀況二:配置文件爲這樣
# config.py class Development(object): DEBUG = True CONFIG_DICT = { 'development': Development }
from flask import Flask app = Flask(__name__) app.config.from_object('config') # 這樣導入 def hello(): return 'hello' app.add_url_rule('/hello', view_func=hello) if __name__ == '__main__': app.run(debug=app.config["CONFIG_DICT"]["development"].DEBUG)
還能夠這樣導入,這個是從同事那裏偷學來的。這種形式我感受比較好
from flask import Flask from config import CONFIG_DICT app = Flask(__name__) app.config.from_object(CONFIG_DICT["development"]) # 這樣導入就能夠直接用你類中定義的變量了 def hello(): return 'hello' app.add_url_rule('/hello', view_func=hello) if __name__ == '__main__': # print(app.config["DEBUG"]) app.run(debug=app.config["DEBUG"])
route() 裝飾器把一個函數綁定到對應的 URL 上。
添加路由的兩種方式:
# 路由方式一(*):裝飾器 @app.route('/index',methods=['GET','POST']) #當有post提交時 def index(): return "Index"
#路由方式二 路由方式一種的裝飾器也是用的這種方法 def order(): return 'Order' app.add_url_rule('/order',view_func=order)#view_func綁定那個函數
咱們不只能夠爲視圖函數綁定多個url,還能夠在URL規則中添加變量部分,使用"<變量名>"的形式表示.Flask會把變量傳入到視圖函數中.
格式爲: <轉換器的類型:參數名稱> 轉換器(其實就是要求參數的格式類型)。
from flask import Flask app=Flask(__name__) @app.route('/index/<int:id>/') #參數id要求爲int類型 def index(id):#別忘記傳參 return 'Hello Flask%s'%(id) if __name__ == '__main__': app.debug=True app.run()
當url規則中包含變量時,若是用戶訪問的URL沒有添加變量,好比/index,那麼服務器會報一個404錯誤,一般狀況下咱們會在app.router裝飾器中使用defaults參數設置url變量的默認值,這個參數做爲字典來輸入.
from flask import Flask app=Flask(__name__) @app.route("/index,defaults={'id':1} @app.route('/index/<int:id>/') def index(id): return 'Hello Flask%s'%(id) if __name__ == '__main__': app.debug=True app.run()
轉換器有下面幾種:
@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, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, }
router中的url一個/和兩個/的區別?
惟一 URL / 重定向行爲 Flask 的 URL 規則基於 Werkzeug 的路由模塊。這個模塊背後的思想是基於 Apache 以及更早的 HTTP 服務器主張的先例,保證優雅且惟一的 URL。 以這兩個規則爲例: @app.route('/projects/') def projects(): return 'The project page' @app.route('/about') def about(): return 'The about page' 雖然它們看起來着實類似,但它們結尾斜線的使用在 URL 定義 中不一樣。 第一種狀況中,指向 projects 的規範 URL 尾端有一個斜線。這種感受很像在文件系統中的文件夾。
訪問一個結尾不帶斜線的 URL 會被 Flask 重定向到帶斜線的規範 URL 去。 然而,第二種狀況的 URL 結尾不帶斜線,相似 UNIX-like 系統下的文件的路徑名。訪問結尾帶斜線的 URL 會產生一個 404 「Not Found」 錯誤。 這個行爲使得在遺忘尾斜線時,容許關聯的 URL 接任工做,與 Apache 和其它的服務器的行爲並沒有二異。此外,也保證了 URL 的惟一,有助於避免搜索引擎索引同一個頁面兩次。
構造url(反向解析)
web程序中的URL無處不在,若是程序中的url都是以硬編碼的方式(即完整的url)寫出,那麼將會大大的下降代碼的易用性,好比你修改了某一個路由規則,那麼在視圖中對應的url都要修改一遍,爲解決這個問題,url_for函數就出現了,你在視圖中直接用url_for(函數名),就能夠獲取真正的URL了.注意這裏得到是相對路徑只能在程序內部使用.
注意:endpoint不寫,別名默認視圖函數名字
from flask import Flask,url_for#反向解析須要導入url_for 至關於Django中的reverse app=Flask(__name__) @app.route('/aa/',endpoint='index') #endpoint至關於django中的name,主要是起別名的做用 def index(): v=url_for('login')#反向解析 print(v)#打印 return '這是index頁面' @app.route('/login/',endpoint='login') def login(): return '這是登陸頁面' if __name__ == '__main__': app.run(debug=True)
結果:
/login/
自定義正則轉換器
當工做中遇到url中傳遞正則表達式的狀況,咱們能夠自定義正則表達式轉換器
首先咱們要繼承BaseConverter這個正則類,咱們來看一下源碼
class BaseConverter(object): """Base class for all converters.""" regex = '[^/]+' #這裏就是正則表達式,若是咱們不寫就用它的 weight = 100 #這裏沒看懂 def __init__(self, map): self.map = map def to_python(self, value): #這裏對用正則取到的數據是否進行修飾,默認沒有修飾 return value def to_url(self, value): #這個方法就是咱們用url_for方法時,所調用的方法 return url_quote(value, charset=self.map.charset)
咱們如今的項目需求是,用戶傳過來的參數,uid前綴返回給視圖函數
class RegexConverter(BaseConverter): def __init__(self, url_map, regex): super(RegexConverter, self).__init__(url_map) # 繼承map self.regex = regex # 輸入咱們本身的正則表達式,用來替代基類中的regex def to_python(self, value): return "uid" + value def to_url(self, value): "這裏沒動" val = super(RegexConverter, self).to_url(value) return val app.url_map.converters['regs'] = RegexConverter #在app.route裝飾器中咱們定義正則時前綴要使用regs,不然它會匹配不到 @app.route('/index/<regs("\d+"):nid>', methods=["GET"]) def index(nid): print("nid的結果:", nid) return "這是index頁面"
咱們這樣在前端輸入
後端的結果爲:
nid的結果爲: uid22
注意這裏有一個坑:咱們定義了正則前端輸入的參數就必須是咱們正則中要求的,不然會報錯,不能輸入127.0.0.1:3000/index/22aa 這樣是匹配不出來的
這是另外的一個例子
from flask import Flask ,render_template,redirect,url_for from werkzeug.routing import BaseConverter #自定義正則表達式就要繼承BaseConverter這個類 app=Flask(__name__) class RegexConverter(BaseConverter): ''' 自定義url匹配正則表達式轉換器 ''' def __init__(self,map,regex): super(RegexConverter,self).__init__(map) self.regex=regex def to_python(self, value): ''' 路由匹配時,匹配成功後傳遞給視圖函數中的參數值 :param value: :return: ''' return int(value) def to_url(self, value): ''' 使用url_for反向生成url時,傳遞的參數通過該方法處理,返回的值用於生成URL中的參數 :param value: :return: ''' val=super(RegexConverter, self).to_url(value) return val
#先要把你寫的正則轉換器添加到Flask的轉換器中 app.url_map.converters['regs']=RegexConverter
@app.route('/index/<regs("\d+"):nid>',methods=['GET','POST']) #使用自定義的轉換器 def index(nid): print(nid,type(nid)) v=url_for("index",nid=555)#至關於/index/555 print(v) return "這是Index頁面" if __name__ == '__main__':
重定向
當須要重定向時.能夠用rediret_to參數
from flask import Flask,render_template,redirect app = Flask(__name__) @app.route('/index',methods=['GET','POST'],redirect_to='/new') def index(): return "老功能" @app.route('/new',methods=['GET','POST']) def new(): return '新功能' if __name__ == '__main__': app.run()
獲取子域名
首先咱們要知道:域名是由子域名和頂級域名構成的.
一級域名:又叫頂級域名,一串字符串中間一個點隔開,例如baidu.com,這裏說明一下,www.baidu.com不是一級域名!!而是二級域名!
二級域名:實際上就是一個一級域名如下的主機名,一串字符串中間兩個「.」隔開,例如pan.baidu.com("pan"就是主機名)。
三級域名:二級域名的子域名,特徵是包含三個「.」,通常來講三級域名都是免費的。
#這是頂級域名 https://baidu.com/ #這是頂級域名的子域名
https://www.baidu.com/
https://pan.baidu.com
from flask import Flask,url_for#反向解析須要導入url_for 至關於Django中的reverse app=Flask(__name__) @app.route('/aa/',subdomain="admin") def index(): v=url_for('login')#反向解析 print(v) return '這是index頁面'
@app.router中的參數
@app.route和app.add_url_rule參數: rule, URL規則 view_func, 視圖函數名稱 defaults=None, 默認值,當URL中無參數,函數須要參數時,使用defaults={'k':'v'}爲函數提供參數 endpoint=None, 名稱,用於反向生成URL,即: url_for('名稱') methods=None, 容許的請求方式,如:["GET","POST"] strict_slashes=None, 對URL最後的 / 符號是否嚴格要求, 如: @app.route('/index',strict_slashes=False), 訪問 http://www.xx.com/index/ 或 http://www.xx.com/index都可 @app.route('/index',strict_slashes=True) 僅訪問 http://www.xx.com/index redirect_to=None, 重定向到指定地址 如: @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 或 def func(adapter, nid): return "/home/888" @app.route('/index/<int:nid>', redirect_to=func) subdomain=None, 子域名訪問 from flask import Flask, views, url_for app = Flask(import_name=__name__) app.config['SERVER_NAME'] = 'haiyan.com:5000' @app.route("/", subdomain="admin") def static_index(): """Flask supports static subdomains This is available at static.your-domain.tld""" return "admin.xxx.com" #動態生成 @app.route("/dynamic", subdomain="<username>") def username_index(username): """Dynamic subdomains are also supported Try going to user1.your-domain.tld/dynamic""" return username + ".your-domain.tld" if __name__ == '__main__': app.run()
其實Flask咱們用的最多的就是FBV,CBV用的不多,
這裏簡單介紹下CBV
from flask import Flask, views from functools import wraps import time app = Flask(__name__) def cal_time(func): """ 計算請求所用的時間 :param func: :return: """ wraps(func) def inner(*args, **kwargs): start_time = time.time() result = func() end_time = time.time() print(f'該函數執行了{end_time - start_time}s秒') return result return inner class Login(views.MethodView): methods = ['POST', 'GET'] # 若是須要在CBV中加裝飾器的話,括號裏就是裝飾器的名字,能夠傳多個,當有一個的時候別忘記了加逗號(,) decorators = (cal_time,) def get(self): time.sleep(1) print('get 請求') return 'login get' def post(self): time.sleep(2) print('post 請求') return 'login post' app.add_url_rule('/login', view_func=Login.as_view(name='login')) # name=endpoint if __name__ == "__main__": app.run(debug=True, host='127.0.0.1', port=5001)
當咱們在Flask中的視圖中添加裝飾器時.咱們要添加的裝飾器和路由裝飾器會出現衝突,這時候應該辦
首先咱們要肯定的路由裝飾器必定要先放到咱們的裝飾器的上邊,由於它要先執行,才能再執行咱們的裝飾器,
當咱們有多個視圖函數須要裝飾時候,好比這樣
from flask import Flask#導入Flask類 app=Flask(__name__) def wrapper(f): def inner(*args,**kwargs): print('before') return f() return inner @app.route('/index1') @wrapper def index(): return 'Hello Flask' @app.route('/login') @wrapper def login(): return 'Hello Flask' if __name__ == '__main__': print(type(__name__)) app.run(debug=True)
這時候就會出現錯誤
ssertionError: View function mapping is overwriting an existing endpoint function: inner
由於 endpoint默認反向生成函數名,然而,被裝飾的函數的真正的函數名都是inner,因此endpoint這時候就出錯了,這時候咱們就須要真正的函數名,因而就用到了wraps裝飾器修復
from flask import Flask from functools import wraps #導入wraps app=Flask(__name__) def wrapper(f): @wraps(f) def inner(*args,**kwargs): print('before') return f() return inner @app.route('/index1') @wrapper def index(): return 'Hello Flask' @app.route('/login') @wrapper def login(): return 'Hello Flask' if __name__ == '__main__': print(type(__name__)) app.run(debug=True)
HTTP有許多訪問url的方法,在默認狀況下,只支持GET方法,可是,能夠定義router中的參數來實現多種HTTP方法
好比當時post請求的時候
@app.route('/login',methods=['GET','POST']) #這裏的括號裏就要有method參數了
首先咱們應該知道,djano中的請求數據是經過參數request傳遞給視圖函數的,可是在Flask不是經過參數傳遞進來的,而是經過上下文管理
首先從 flask 模塊裏導入它:
from flask import request
當前請求的 HTTP 方法可經過 method 屬性來訪問。經過:attr:~flask.request.form 屬性來訪問表單數據( POST 或 PUT 請求提交的數據)。
當訪問form表單數據(POST提交)時
request.form.get()
注意:不存在時,獲得的值爲None.
當訪問url參數(get提交時)
request.args.get()
注意:不存在時,獲得的值爲None.
請求相關信息 # request.method 請求方法 # request.args 當get請求,這裏獲得的是不可變的字典,也就是不可改變該字典裏的數據,若是要變爲可變字典,能夠用to_dict() # request.form 當post請求時 # request.get_json() #當contentType只能是json時,還能夠經過設置參數force=True 將忽視contentType # request.values # request.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
# request.remote_add 獲取用戶ip
# obj = request.files['the_file_name'] # obj.save('/var/www/uploads/' + secure_filename(f.filename))
重點來介紹一下
1.request.values()
此方法能夠獲取get請求和post請求的全部的參數
print(request.values) # CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '20')]), ImmutableMultiDict([('user', 'Oldboy'), ('pwd', 'DragonFire')])]) print(request.values.get("id")) # 1 print(request.values["user"]) # Oldboy # 這回喜歡直接操做字典的小夥伴們有驚喜了! to_dict() 方法能夠直接將咱們的參數所有轉爲字典形式 print(request.values.to_dict()) # {'user': 'Oldboy', 'pwd': 'DragonFire', 'id': '1', 'age': '20'} # 注意這裏的坑來啦! 坑來啦! # 若是url和form中的Key重名的話,form中的同名的key中value會被url中的value覆蓋 # http://127.0.0.1:5000/req?id=1&user=20 print(request.values.to_dict()) # {'user': 20 'pwd': 'DragonFire', 'id': '1'}
# 響應相關信息 return "字符串" #返回字符串 return render_template('html模板路徑',**{}) #渲染模板 return redirect('/index.html') #重定向 return json.dumps() #返回json數據,和他同樣的就是jsonify()
設置響應頭和cookie
#####如何設置響應頭和cookie*******
response = make_response(render_template('index.html') ) #生成對象
#response是flask.wrappers.Response類型
response.set_cookie('key', 'value') #設置cookie
response.delete_cookie('key') #刪除cookie
response.headers['X-Something'] = 'A value' #設置響應頭
return response #返回respon對象
from urllib.parse import urlencode,quote,unquote val = "%E6%8A%8A%E5%87%A0%E4%B8%AA" print(unquote(val)) #ba上面這樣的數據轉換成中文 vall='我是中國人' print(quote(vall)) vdd={"name":'小紅'} print(urlencode(vdd))
大多數和djano的模板渲染差很少
首先要創建一個名爲templates的文件在根目錄下,文件夾中放html
from flask import Flask,render_template app=Flask(__name__) @app.route('/xxx') def xxx(): return render_template('/index.html',msg='fdsfd') if __name__ == '__main__': print(type(__name__)) app.run(debug=True)#至關於run_simple('localhost',5000,index),
一、爲了防止xss攻擊,加了驗證,因此頁面上顯示字符串的形式,解決辦法,有兩種方式
- 方法一在後端Markup
v5 = Markup("<input type='text' />")
-方法二 在前端
{{ v4|safe }}
二、自定義方法
def test(a,b): return a+b @app.route('/index') def index(): return render_template("index2.html",test=test) index2.html <h1>{{ test(1,2) }}</h1>
三、寫一個函數在全部的頁面都使用
template_global和template_filter
@app.template_global() def sb(a1, a2): return a1 + a2 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3
調用方式:{{sb(1,2)}} {{ 1|db(2,3)}}
四、模板繼承:和django的同樣。extents
5.後端傳函數,前端使用模板語言的時候須要加括號然而djano不須要
def sb(a1, a2): content={ 'k1':lambda x:5 } return render_template('index.html',**content) #前端 {{k1()}}
模板其餘問題參考django
它容許你在不一樣請求間存儲特定用戶的信息。
Flask中的session和djano中的session是不一樣的,Flask中的session放到cookie中,它是在 Cookies 的基礎上實現的,而且對 Cookies 進行密鑰簽名。這意味着用戶能夠查看你 Cookie 的內容,但卻不能修改它,除非用戶知道簽名的密鑰。
一個完整的範例
要求 登錄後把信息添加session中
flask.py
from flask import Flask,render_template,request,redirect,session app=Flask(__name__) app.secret_key='wefjldsaj' #先要進行密鑰簽名 USER_DICT={ '1':{'name':'小明'}, '2':{'name':'小紅'}, '3':{'name':'36'} }#模擬一個數據庫 @app.route('/login',methods=['GET','POST']) def login(): print('請求來了') if request.method=="POST": username=request.form.get('username')#從form表單中取數據 password=request.form.get('password') #request.args #對應get從url中取數據 if username=='alex' and password=="123": #登陸成功後把用戶信息放入session中 session['user_info']=username return redirect('/index') else: return render_template('/login.html',msg="用戶名和密碼錯誤") #還能夠這樣傳值return render_template('/login.html',**{'msg':"用戶名和密碼錯誤"}) return render_template('/login.html') @app.route('/index') def index(): """ 主頁 :return: """ username=session.get('user_info') if not username: return redirect('/login') print(USER_DICT) return render_template('/index.html',user_dict=USER_DICT) @app.route('/logout') def logout(): session.pop('user_info',None) return '已經退出' if __name__ == '__main__': app.run(debug=True)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!--IE瀏覽器最高渲染--> <meta name="viewport" content="width=device-width, initial-scale=1"> <!--爲了確保適當的繪製和縮放--> <title>主頁</title> <link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css"> </head> <body> <ul> {% for k,v in user_dict.items() %} <li>{{v.name}}</li> {% endfor%} </ul> <script src="../jquery-3.2.1.min.js"></script> </body> </html>
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!--IE瀏覽器最高渲染--> <meta name="viewport" content="width=device-width, initial-scale=1"> <!--爲了確保適當的繪製和縮放--> <title>用戶登陸</title> <link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css"> </head> <body> <h1>請登陸</h1> <form method="post"> 用戶名:<input type="text" name="username"> 密碼: <input type="password" name="password">{{msg}} <input type="submit" value="提交"> </form> <script src="../jquery-3.2.1.min.js"></script> </body> </html>
from flask import Flask,url_for,session app = Flask(__name__) app.secret_key = "sdsfdgdgdgd" app.config['SESSION_COOKIE_NAME'] = 'session_lvning' #設置session的名字 @app.route('/index/') def index(nid): #session本質上操做的是字典, session是否還有其餘方法?與字典方法相同 #session的原理:若是下一次訪問的時候帶着隨機字符串,會把session裏面對應的 # 值拿到內存,假設session保存在數據庫,每執行一次連接一次數據庫,每次都要時時更新的話 # 會很是損耗內存 session["xxx"] = 123 session["xxx2"] = 123 session["xxx3"] = 123 session["xxx4"] = 123 del session["xxx2"] #在這刪除了,真正存儲的時候是沒有xxx2的 return "ddsf" if __name__ == '__main__':
通常一個用戶操做完成後,咱們要告訴用戶操做的結果,用戶看完後這個消息就不必存在了,咱們就能夠刪除它.
Flask的消息閃現系統就是提供了這個功能.也就是反饋
flask()它能夠將要閃現的內容存儲起來.
get_flashed_messages():它能夠把儲存的內容取出來顯示,而後自動刪掉.
本質:閃現是基於session建立的,flash支持往裏邊放值,只要你取一下就沒有了,至關於pop了一下。不只把值取走,並且吧session裏的東西去掉,能夠用session直接寫
from flask import Flask,flash,get_flashed_messages app = Flask(__name__) app.secret_key = 'asdfasdfasdf' @app.route('/x1',methods=['GET','POST']) def login(): flash('我要上向龍',category='x1') #把內容放入flash中,category就是一個別名 return '視圖函數x1' @app.route('/x2',methods=['GET','POST']) def index(): data = get_flashed_messages(category_filter=['x1']) #取數據 print(data) return "視圖函數x2" if __name__ == '__main__': app.run()
先執行一次/x1
執行兩次/X2
結果
['我要上向龍'] [] #第二次就取不出值來了
用的場景: 閱後即焚
登陸場景:
flash.py
rom flask import render_template, request, session, url_for, redirect, flash @app.route('/') def index(): if 'user' in session: return render_template('hello.html', name=session['user']) else: return redirect(url_for('login'), 302) @app.route('/login', methods=['POST', 'GET']) def login(): if request.method == 'POST': session['user'] = request.form['user'] flash('Login successfully!') return redirect(url_for('index')) else: return ''' <form name="login" action="/login" method="post"> Username: <input type="text" name="user" /> </form>
login.html
!doctype html> <title>Hello Sample</title> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}"> {% with messages = get_flashed_messages() %} {% if messages %} <ul class="flash"> {% for message in messages %} <li>{{ message }}</li> {% endfor %} </ul> {% endif %} {% endwith %} <div class="page"> {% block body %} {% endblock %} </div>
@app.before_request和@app.after_request
app.before_request和app.after_request至關於djano中的中間件函數process_request和process_response,服務於全局,
不一樣點:當before_request有返回值時.它會直接執行全部的after_request,而不是像djano中執行對應的after_request函數
#after_request 若是沒有拋出錯誤,在每次請求後執行 接受一個參數:視圖函數做出的響應 在此函數中能夠對響應值在返回以前作最後一步修改處理 須要將參數中的響應在此參數中進行返回 @app.after_request def after_request(response): return response ———————————————— 版權聲明:本文爲CSDN博主「csdn-gdj」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。 原文連接:https://blog.csdn.net/guodejie/article/details/80795770
項目中遇到的知識點: 在項目中咱們用after_request全局裝飾器,裝飾了一個跨域函數
from flask import Flask,session app=Flask(__name__) app.secret_key="dfsadsfds" @app.route('/login') def login(): session['login_info']=123 return '123' @app.route('/index3') def index(): ret=session.pop('login_info') print('ret',ret) return '這是主頁' @app.before_request def before(): print('brefore') @app.after_request def after(response): #注意這裏的參數和返回值 print('after') return response if __name__ == '__main__': app.run(debug=True) app.__call__
結果:
brefore
after
還有其餘的一些全局裝飾器
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, Request, render_template app = Flask(__name__, template_folder='templates') app.debug = True @app.before_first_request def before_first_request1(): print('before_first_request1') @app.before_first_request def before_first_request2(): print('before_first_request2') @app.before_request def before_request1(): Request.nnn = 123 print('before_request1') @app.before_request def before_request2(): print('before_request2') @app.after_request def after_request1(response): print('before_request1', response) return response @app.after_request def after_request2(response): print('before_request2', response) return response @app.errorhandler(404) def page_not_found(error): return 'This page does not exist', 404 @app.template_global() def sb(a1, a2): return a1 + a2 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 @app.route('/') def hello_world(): return render_template('hello.html') if __name__ == '__main__': app.run()
這個中間件是發生在request造成以前,也就是在執行app.wsgi_app()以前添加一些操做,經過對象的__call__方法
沒多大用處,通常咱們用@app.before_request
from flask import Flask from flask import session, request app = Flask(__name__) app.secret_key = 'asdfasdfasdf' @app.route('/x2',methods=['GET','POST']) def index(): print('我是index') return "我是x2" class Middleware(object): def __init__(self,old_wsgi_app): """ 服務端啓動時,自動執行 :param old_wsgi_app: """ self.old_wsgi_app =old_wsgi_app def __call__(self, environ, start_response): """ 每次有用戶請求道來時 :param args: :param kwargs: :return: """ print('before')#添加在造成request以前的操做 obj = self.old_wsgi_app(environ, start_response) print('after') #添加在造成request以後的操做 return obj if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run() """ 執行app.run()時候 1.先執行app.__call__, 2.再調用app.wsgi_app(),由於我本身有wsgi_app屬性,加括號執行個人__call__方法,而後就把老的app.wsgi_app傳進來,這樣咱們就能夠在老的app.wsgi_app執行前,和執行後作一些操做 """
結果:
before
我是index
after
詳情見flask組件中的數據庫鏈接池
藍圖是什麼?
第一個功能:若是代碼不少要進行歸類,blueprint就是對flask的目錄結構進行劃分(應用於小中型程序),使目錄結構更清晰。
#這個怎麼理解呢? 好比咱們有兩個頁面一個是金融管理,一個會員管理,一個是美食管理。 每一個頁面都有好多的函數,這些函數若是放在一塊兒的話,會有不少代碼,顯得特別的亂。若是咱們能分類這些代碼,把不一樣的代碼放到不一樣py文件中就行了。blueprint就是爲了解決這個問題的。
在每一個py中實例化一個藍圖對象,一共生成三個藍圖對象就能夠了。而後再把這些對象註冊到app中,這樣就方便管理了。
第二個功能:當一個py文件中有多個函數時,爲了使url容易區分能夠給url添加前綴.
第三個功能: 咱們知道@app.before_rerequest對全局生效,然而藍圖可讓它只對某一個藍圖實例生效
咱們爲何要用藍圖?
咱們的應用常常會區分用戶站點和管理員後臺 二者雖然都在同一個應用中,可是風格迥異。把它們分紅兩個應用吧,總有些代碼咱們想重用;放在一塊兒嘛,耦合度過高,代碼不便於管理。因此Flask提供了藍圖(Blueprint)功能。
藍圖使用起來就像應用當中的子應用同樣,能夠有本身的模板,靜態目錄,有本身的視圖函數和URL規則,藍圖之間互相不影響。可是它們又屬於應用中,能夠共享應用的配置。
對於大型應用來講,
咱們能夠經過添加藍圖來擴展應用功能,而不至於影響原來的程序。不過有一點要注意,目前Flask藍圖的註冊是靜態的,不支持可插拔。 轉載於http://www.bjhee.com/flask-ad6.html
例子
首先這樣建立目錄
首先,manage.py文件是咱們的啓動文件
from blue_flask import app if __name__ == '__main__': app.run(debug=True)
admin.py文件中建立一個藍圖實例
from flask import Blueprint ad=Blueprint('ad',__name__,url_prefix='/admin') #實例化一個藍圖對象,給url添加前綴 @ad.route('/ad1') def ad1(): return '這是ad1頁面' @ad.route('/ad2') def ad2(): return '這是ad2頁面'
acount.py文件中咱們再建立一個藍圖實例,並添加一個before_request裝飾器
from flask import Blueprint act=Blueprint('act',__name__) #實例化一個藍圖對象,裏邊的名字隨便起,可是不要和url相同 @act.route('/acount') def login(): return '這是acount' @act.before_request def f (): print('我只對act藍圖實例有效')
__init__.py文件是咱們的初始化文件,在這裏咱們導入藍圖,並註冊藍圖
from flask import Flask #建立一個app對象 app=Flask(__name__) from blue_flask.views.admin import ad from blue_flask.views.acount import act #給新藍圖註冊 app.register_blueprint(ad) app.register_blueprint(act)
這樣咱們就可能夠執行manage.py文件了,
在url中輸入/acount,咱們能夠在前端看到"這是account",在後臺打印出"我只對act藍圖實例有效"
當咱們在url這樣輸入/admin/ad1,在前端會顯示這是ad1頁面,在後臺不會打印出f裝飾器的內容