Flask介紹
對於Flask大家很熟悉了,現在主流python的web框架,除了Django就數Flask了。
Django不用多說,集合了orm、template模板引擎、後臺管理系統、引數驗證、路由系統、使用者認證和其他一些工具的,方便快速建站,主要構建了ORM和複寫ADMIN模組,就可以快速生成網站和後臺增上改查和一些其他的定製化開發。
Flask是一個輕量級的可定製框架,使用Python語言編寫,較其他同類型框架更為靈活、輕便、安全且容易上手。它可以很好地結合MVC模式進行開發,開發人員分工合作,小型團隊在短時間內就可以完成功能豐富的中小型網站或Web服務的實現。另外,Flask還有很強的定製性,使用者可以根據自己的需求來新增相應的功能,在保持核心功能簡單的同時實現功能的豐富與擴充套件,其強大的外掛庫可以讓使用者實現個性化的網站定製,開發出功能強大的網站。
筆者更傾向於Flask這個框架,因為它更加透明,更能掌控專案的質量。
使用過的外掛Flask的外掛管理是一個很不錯的特性,我們利用它可以在啟動web服務之前載入我們所需要的外掛,一下是筆者經常用到的:
flask-restfulflask的restapi開發框架,有引數校驗,路由攔截等功能。
flask-sqlalchemySqlalchemy的flask外掛,這個外掛作者擴充套件了針對與session中的query的分頁功能,可以使用SQLALCHEMY_BINDS進行多個數據庫的繫結,可以配置連線池,連線池過期時間。
mysqlclient或者pymysqlSqlalchemy連線mysql的引擎,不過pymysql需要加入一句話:
import pymysql pymysql.install_as_MySQLdb()
marshmallow
Sqlalcemy序列化資料利器,可以使用它針對query返回的QuerySet結果集合進行序列化成dict 資料。
flask-cors開發API會遇到跨域訪問的問題,可以就是客戶端OPTIONS的請求,先探知伺服器允不允許跨域訪問,允許會返回header中允許那些方法進行請求伺服器(GET、POST、DELETE、PUT等),這個外掛可以透過簡單的配置,讓您的服務允許跨域訪問,不過在生產環境,還是推薦使用nginx的好,能夠使用lua語言進行更加嚴格的控制。
flask-login或者flask-jwt-extended這兩個都是使用者認證用到的外掛,使用session控制,選擇flask-login,使用jwt使用flask-jwt-extended。
Flask框架下面簡單說一下flask的框架,flask框架是基於Werkzeug和Jinja2兩大基礎框架,Werkzeug是基於WSGI協議的框架,已經有了基本的路由、資料結構、請求和響應等功能,在此之上Flask擴充套件了一些特性:
requestFlask利用Werkzeug的Local、LocalStack和LocalProxy,實現了AppContext和RequestContext的執行緒或者協程安全功能,也就是:
當請求過來,Flask將app_context和request,這兩個物件壓入一個執行緒號或者協程號對應的棧中,說白了就是dict字典,執行緒或者攜程號有get_indent內建方法獲得請求過程中,由棧彈出上次壓入棧中的app_context和request請求結束釋放空間另外說明flask-sqlalchemy利用執行緒或者攜程號有get_indent,可以使用scope_session功能,將session隔離,它是執行緒或者協程安全的,也和flask的請求保持一致。
endpoint使得每個view方法,有個名稱,這個名稱是唯一的,它能夠透過這個名稱找到這個檢視方法,也就能夠獲得路由。
這裡資料結構簡單地說就是一個map型別,一個名稱唯一對應一個檢視方法,不允許相同的endpoint出現,這個應用在使用url_for這個方法上:
程式中使用url_for進行路由跳轉template模板總是用url_for查詢對應的路由這樣可以靈活根據名稱去使用路由,而不是硬編碼到程式中非常死板,如果說我們修改了一個url的地址,只是微小的修改,其他引用這個路由的地方也需要修改,我們可能忘記了使用它的地方,這時url_for非常好的解決了這個問題。
extentions擴充套件應用,提供了兩種方式,一種是直接載入,之類用生成物件例如CORS(flask_app),也可以懶載入,在建立應用之前定義物件,建立flask_app時載入外掛,例如flask-sqlalchemy
from flask import Flaskfrom flask_sqlalcemy import Sqlalchemydb = Sqlalchemy()def create_app(): """ 建立Flask app """ f_app = Flask() f_app.config.from_object("core.settings") db.init_app(app=f_app) return f_app
這樣的形式,我們可以使用全域性這個db物件了。
開發專案目錄結構我們可以借鑑django的目錄形式進行組織專案的框架,例如:
core資料夾基本這個樣子,app 是專案Flask應用初始化,settings是配置資訊,應用是user和config等,static存放靜態檔案,templates是模板目錄,requirements.txt裡面配置依賴,run.py是除錯使用的啟動入口。
特別的一個應用目錄為:
其中,__init__.py是module的檔案,dbis.py裡面都是面向資料操作的方法,models.py裡面都是ORM的定義,urls.py裡面是路由配置,validators.py存放參數校驗方法,views.py存放檢視方法,serializers.py存放序列化的方法,dbi_services.py存放構造views.py中使用的資料型別。
我們如何將他們和Flask的應用聯絡起來呢,可以進行如下操作:
生成Flask的應用程式碼:
import osfrom flask_sqlalchemy import SQLAlchemyfrom flask_bootstrap import Bootstrapfrom flask_url.conf import FlaskUrlConffrom flask_wtf.csrf import CSRFProtectfrom flask import Flaskdb = SQLAlchemy()def create_app(import_name): """ 建立Flask應用 :param import_name: [str] 模組名稱 :return: """ f_app = Flask(import_name) # 根據環境變數載入配置資訊 env_dict = { "DEV": "core.dev_settings", "ONLINE": "core.online_settings" } env = os.environ.get("PRO_ENV", "DEV") f_app.config.from_object(env_dict.get(env, "core.dev_settings")) FlaskUrlConf(app=f_app) db.init_app(app=f_app) CSRFProtect(app=f_app) print(f_app.url_map) return f_appapp = create_app(__name__)
其中使用了FlaskUrlConf(app=f_app)這個,是我自己構造的一個外掛,貼出這段程式碼:
from flask import Flaskfrom flask.blueprints import Blueprintfrom flask_url.utils import get_mod_attrdef path(rule, endpoint, view_func, **options): return Url(rule=rule, endpoint=endpoint, view_func=view_func, **options)class Url: rule = None endpoint = None view_func = None options = {} def __init__(self, rule, endpoint, view_func, **options): self.rule = rule self.endpoint = endpoint self.view_func = view_func self.options = optionsclass FlaskUrlConf: def __init__(self, app: Flask = None): if app: self.init_app(app=app) def init_app(self, app: Flask): install_apps = app.config.get("INSTALL_APPS", []) for app_str in install_apps: mod_path = f"{app_str}.urls" try: urls = get_mod_attr(mod_path, "urls") b = Blueprint(import_name=mod_path, name=app_str) for url in urls: if isinstance(url, Url): b.add_url_rule( rule=url.rule, endpoint=url.endpoint, view_func=url.view_func, **url.options ) app.register_blueprint(b) except ImportError as e: app.logger.warn(f"Import module {mod_path} err {e}") except IndexError as e: app.logger.warn(f"Split module {mod_path} attr error {e}") except AttributeError as e: app.logger.warn(f"Get attr from url module {mod_path}, error {e}")
其核心思想是透過INSTALL_APPS這個配置,將各級模組兒應用下的urls.py中的urls列表進行載入,urls.py示例:
from flask_url.conf import pathfrom article import viewsurls = [ path(rule="/article/page/<int:a_id>/", view_func=views.get_article, endpoint="page")]
那我們就完成了MVC的專案目錄結構的搭建。
部署最後我們再來談一下flask應用的部署,我們可以使用gunicorn或者uwsgi進行部署,透過nginx進行代理即可。
uwsgi配置示例:
uwsgi]uid = rootgid = rootmaster = trueprocesses = 1listen = 10socket = 127.0.0.1:9000pidfile = /uwsgi.pid # 你的路徑vacuum = truedaemonize = /uwsgi.log # 你的日誌路徑chdir = ${你的專案路徑}home=${你的env的路徑}buffer-size = 32768 # 可以修改允許最大交換資料module = core.wsgi # 你的 wsgi模組路徑callable = app # 選擇你的應用,Flask的應用http-websockets = true # 是否啟用web socketgevent = 10 # 啟用協程async = 10
nginx配置示例