一、Flask了解

#flask是一個基於python開發並且依賴jinja2和Werkzeug服務的微型框架 對於werkzeug本質是socket服務端,其用於接收http請求並對請求進行預處理,然后觸發flask框架,開發人員基於flask框架提供的功能對請求進行相應的處理,並返回給客戶,如果返回給用戶復雜的內容時,需要借助jinja2模板來實現對模板的處理,即:將模板和數據進行渲染,將渲染后的字符串返回給用戶的瀏覽器 “微(micro)”並不代表你需要把整個web應用塞進單個python文件(雖然確實可以),也不意味着flask在功能上有所欠缺,微框架中的“微"意味着flask旨在保持核心簡單而易於擴展,Flask 不會替你做出太多決策——比如使用何種數據庫。而那些 Flask 所選擇的——比如使用何種模板引擎——則很容易替換。除此之外的一切都由可由你掌握。如此,Flask 可以與您珠聯璧合。 默認情況下,Flask 不包含數據庫抽象層、表單驗證,或是其它任何已有多種庫可以勝任的功能。然而,Flask 支持用擴展來給應用添加這些功能,如同是 Flask 本身實現的一樣。眾多的擴展提供了數據庫集成、表單驗證、上傳處理、各種各樣的開放認證技術等功能。Flask 也許是“微小”的,但它已准備好在需求繁雜的生產環境中投入使用
1、安裝
pip3 install flask
2、werkzeug簡介
安裝flask后自動就有werkzeug
Werkzeug是一個WSGI工具包,他可以作為一個Web框架的底層庫。這里稍微說一下, werkzeug 不是一個web服務器,也不是一個web框架,而是一個工具包,官方的介紹說是一個 WSGI 工具包,它可以作為一個 Web 框架的底層庫,因為它封裝好了很多 Web 框架的東西,例如 Request,Response 等等

from werkzeug.wrappers import Response,Request @Request.application def hello(request): #wsgi協議需要兩個參數,env和response,這里只有一個參數,不符合該協議, #werkzeug是個工具包,在wsgi基礎上又做了封裝,所以傳一個參數就行 def hello(request): return Response('Hello World!') if __name__ == '__main__': from werkzeug.serving import run_simple run_simple('localhost', 4000, hello) #三個參數分別是跑的地址,跑的端口,最后一個是可調用對象
3、對比django
#對應django中的三件套 Httprespose '' render render_template redirect redirect JsonResponse jsonify
二、flask的使用
1、flask最簡單的模板
from flask import Flask # 實例化產生一個Flask對象 app = Flask(__name__) #flask的路由是基於裝飾器的 @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() # 看源碼發現,最終調用了werkzeug的run_simple()
2、flask登陸

from flask import Flask, request, render_template, redirect app = Flask(__name__) USERS = { 1: {'name': '張三', 'age': 18, 'gender': '男', 'text': "道路千萬條"}, 2: {'name': '李四', 'age': 28, 'gender': '男', 'text': "安全第一條"}, 3: {'name': '王五', 'age': 18, 'gender': '女', 'text': "行車不規范"}, } #methods=['GET','POST'] 該路由運行get請求和post請求,沒寫默認只允許get請求 @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': # HTML文件放在templates(自己創建的)中,實例化的過程中app=Flask(__name__),點Flask進去,看到template_folder="templates", return render_template('login.html') else: # request.form相當於django中的POST,注意不是from.是form name = request.form.get('name') pwd = request.form.get('pwd') if name == 'pdun' and pwd == '123': return redirect('/') else: # django中傳字典,這里傳字典打散,**字典 return render_template('login.html', error="用戶名或密碼錯誤") @app.route('/') def index(): return render_template('index.html', user=USERS) @app.route('/detail/<int:id>') def detail(id): user = USERS[id] return render_template('detail.html', user=user) if __name__ == '__main__': app.run()
需要的HTML

#detail.HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>詳細信息 {{user.name}}</h1> <div> {{user.text}} </div> </body> </html> #index.HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> {% for k,v in user.items() %} <tr> <td>{{k}}</td> #三種取值方式 <td>{{v.name}}</td> <td>{{v['name']}}</td> <td>{{v.get('name')}}</td> <td><a href="/detail/{{k}}">查看詳細</a></td> </tr> {% endfor %} </table> </body> </html> #login.HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用戶登錄</h1> <form method="post"> <input type="text" name="name"> <input type="text" name="pwd"> <input type="submit" value="登錄">{{error}} </form> </body> </html>
3、配置文件
3.1、修改配置的兩種方式
#1.直接對app.config進行修改 app.config["DEBUG"] = True #2.使用類/模塊的方式導入 #首先要有一個settings.py的文件 #在啟動文件中導入 app.config.from_object("settings.FlaskSetting")

#settings.py class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): #創建類繼承Config,重寫屬性, DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): #外界使用哪個,導入哪個 DEBUG = True class TestingConfig(Config): TESTING = True #settings.py文件默認路徑要放在程序根目錄,如果想更改 需要修改源碼實例化過程中的最后兩個參數, instance_relative_config=True, root_path=#setting文件的位置 ---------------------------------------------- #然后在啟動文件中就可以這么寫 from flask import Flask app = Flask(__name__) # type:Flask #app.config.from_object("settings.FlaskSetting")

#不常用的幾種方法 #1、通過py文件配置 app.config.from_pyfile("python文件名稱") 如: settings.py DEBUG = True 2、app.config.from_pyfile("settings.py") #通過環境變量配置 app.config.from_envvar("環境變量名稱") #app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) 環境變量的值為python文件名稱名稱,內部調用from_pyfile方法 3、app.config.from_json("json文件名稱") JSON文件名稱,必須是json格式,因為內部會執行json.loads 4、app.config.from_mapping({'DEBUG': True}) 字典格式
3.2、Flask的配置是在app.config中添加的鍵值對,但是存進去的鍵必須是config中存在的,否則它會默認無用,就那么干撩着,下面看看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, }
3.3、實例化的過程中傳參
#上面的類導入法是對已經實例化的app進行的配置, #那么在Flask實例化的時候,傳遞的參數是什么鬼呢? 其實可以理解為對Flask實例進行的初始配置,這里面的參數是非常好理解,注意關鍵字是非常非常非常好理解
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 # 主模塊所在的目錄的絕對路徑,默認項目目錄
常用的參數有(一般情況下,只修改這些就足夠使用了)
static_folder = 'static', # 靜態文件目錄的路徑 默認當前項目中的static目錄 static_url_path = None, # 靜態文件目錄的url路徑 默認不寫是與static_folder同名,遠程靜態文件時復用 template_folder = 'templates' # template模板目錄, 默認當前項目中的 templates 目錄