首頁>技術>

Flask介紹

對於Flask大家很熟悉了,現在主流python的web框架,除了Django就數Flask了。

Django不用多說,集合了orm、template模板引擎、後臺管理系統、引數驗證、路由系統、使用者認證和其他一些工具的,方便快速建站,主要構建了ORM和複寫ADMIN模組,就可以快速生成網站和後臺增上改查和一些其他的定製化開發。

Flask是一個輕量級的可定製框架,使用Python語言編寫,較其他同類型框架更為靈活、輕便、安全且容易上手。它可以很好地結合MVC模式進行開發,開發人員分工合作,小型團隊在短時間內就可以完成功能豐富的中小型網站或Web服務的實現。另外,Flask還有很強的定製性,使用者可以根據自己的需求來新增相應的功能,在保持核心功能簡單的同時實現功能的豐富與擴充套件,其強大的外掛庫可以讓使用者實現個性化的網站定製,開發出功能強大的網站。

筆者更傾向於Flask這個框架,因為它更加透明,更能掌控專案的質量。

使用過的外掛

Flask的外掛管理是一個很不錯的特性,我們利用它可以在啟動web服務之前載入我們所需要的外掛,一下是筆者經常用到的:

flask-restful

flask的restapi開發框架,有引數校驗,路由攔截等功能。

flask-sqlalchemy

Sqlalchemy的flask外掛,這個外掛作者擴充套件了針對與session中的query的分頁功能,可以使用SQLALCHEMY_BINDS進行多個數據庫的繫結,可以配置連線池,連線池過期時間。

mysqlclient或者pymysql

Sqlalchemy連線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擴充套件了一些特性:

request

Flask利用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配置示例

9
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 256變4096:分庫分表擴容如何實現平滑資料遷移?