Flask入坑記錄(二) 整理項目結構

結構規劃

上文我們已非常簡陋的方式創建了一個Flask的WebApi應用,項目的結構如下圖所示。
在這裏插入圖片描述
稍微有點編程經驗的同學都會覺得這樣的項目結構真的太簡陋了,最簡單的三層架構裏面只有視圖層(Controller),業務邏輯層,數據接入層都沒有。項目中一點層次感都沒有,那麼我們應該如何調整項目的結構呢?

項目需要什麼

Flask不像ASP.Net Core那樣,創建好項目之後,該有的文件夾都替你創建好,項目的層次結構也比較清晰。在Flask裏我們就需要自己做這項工作。
規劃之前,首先我們要想清楚,一個小型的WebApi應用它需要有什麼東西?

  • Controller模塊(對外接口)
  • Model模塊(業務邏輯)
  • Log模塊(日誌)
  • CORS(跨域)
  • JWT(Json Web Token)
  • Swagger(API在線文檔)
  • Config(項目配置文件讀寫)

業務邏輯層

這裏的業務邏輯層其實是一個非常龐大的概念,畢竟項目中的大部分時間我們都在對業務邏輯進行編碼。所以這裏有必要對其細分一下。

業務邏輯層的細分

其中,Model模塊裏面還能細分爲:

  • 數據表實體類模塊 db_model
  • 數據傳輸類模塊(Data Transfer Object) dto_model
  • 提供數據接入層服務的Service模塊
  • 業務邏輯處理模塊 logic_models
  • 標準回送及各種錯誤碼等定義

關於業務邏輯層(Model)這裏可能會存在爭議,有些小夥伴可能會認爲數據庫相關的東西應該單獨抽離出來,或者業務邏輯上還能繼續細分,每個開發人員都可能會根據自己的經驗有不同的劃分意見,這裏僅僅是我的個人理解請不要過分深究。我的劃分標準就是:只要跟業務邏輯有關係的代碼,統統放到Model層,那如何定義"跟業務邏輯有關係"這個界限呢?我的理解是:只要在兩個業務邏輯完全不同類型項目裏,不能直接複製粘貼使用的都是"跟業務邏輯有關係"的代碼。

請求處理流程

根據以上劃分的業務邏輯層,我們現在可以先整理一下一個Http請求過來之後的處理流程。
請求處理流程
由上圖可以看出,用戶向Controller發起HTTP請求,Controller不對請求進行任何業務邏輯處理,直接丟給LogicModel(業務邏輯模塊)處理,LogicModel負責對請求進行業務邏輯處理,處理時如果需要和數據庫打交道,則調用提供數據接入層服務的Service模塊,由Service模塊統一進行數據庫操作,最後返回結果。LogicModel返回給Controller一個標準統一的Result對象,Controller根據Result對象裏的錯誤碼(應用自定義的錯誤碼),製作相應的HTTP回送(400,200等)返回給用戶。

使用Flask的插件

正如上篇文章所提到的,Flask是一個插件非常豐富的框架,我們在上節中規劃好的項目結構,大部分都能找到現成的插件。以下就是我們需要用到的插件整理。

插件名 用途
flask_jwt_extended 提供JWT驗證
flasgger 提供Swagger的WebApi在線文檔
flask_cors CORS跨域
flask_sqlalchemy 數據庫ORM框架

如果需要連接MySQL數據庫的話,還需要用到pymysql這個庫作爲Connector。

插件的安裝

插件的安裝和正常的Python包安裝是一樣的。
Windows下

pip install {插件名}

Linux下

pip3 install {插件名}

插件的初始化

我們安裝完插件包之後,下一步就是要在項目中調用了。Flask常用的插件一般都會有兩種初始化的方式:

  1. 通過構造函數傳入Flask app對象初始化。
  2. 插件對象實例化之後通過init_app(Flask: app)方法初始化。

這裏推薦使用第二種方法進行初始化,絕大部分的Flask插件都會有init_app這個方法。

整理結構

接下來就可以開始進入正題了,我們應該如何整理Flask項目的結構?在此之前還是要多費一點時間瞭解一下Python的模塊,因爲後續我們的項目大部分都是以模塊爲最小組成部分。

Python的模塊

Python中的模塊可以是一個py文件,也可以是一個文件夾。可以把Python的模塊類比成C#裏的命名空間,只要文件夾中有__init__.py這個文件,那麼這個文件夾就是一個模塊。有需要的小夥伴可以參考以下連接。
Python中的模塊

消除循環依賴

有了模塊的概念之後,細心的小夥伴可能會發現,Flask官方的Demo中引用其他插件其實是存在循環依賴的。Flask app需要引用其插件,而插件的初始化又需要引用Flask app,這就是一個循環依賴。
針對這種情況,我們可以把項目的結構設計成這樣:
首先,項目應該有一個統一啓動入口,在入口處我們創建Flask app實例,再將這個實例傳到各個插件進行初始化。

DemoApp模塊就是我們的Flask Api應用模塊

DemoApp的__init__.py

# -*- coding: utf-8 -*-
from flask import Flask
from flask_cors import CORS
from .models import db_models
from . import log
from . import swagger
from . import jwt


def create_app():
    # 生成WebApp
    app = Flask(__name__)
    # 跨域
    CORS(app, supports_credentials=True)
    # 初始化數據庫映射和鏈接
    db_models.init(app)
    # 初始化日誌組件
    log.init()
    # 註冊Controller
    __register_blueprint__(app)
    # 初始化jwt
    jwt.init(app)
    # 初始化Swagger
    swagger.init(app)
    return app


def __register_blueprint__(app: Flask):
    # 引用Controlls裏面的藍圖並註冊
    from .controllers.DemoController import route_demo
    app.register_blueprint(route_demo, url_prefix='/api')

注意這裏引用的log、swagger、jwt、db_models模塊都是對相應Flask插件的簡單封裝。以jwt爲例。

自己封裝的jwt模塊中的__init__.py

# -*- coding: utf-8 -*-
from flask_jwt_extended import JWTManager
from flask import Flask

# 這個是插件的jwt實例
jwt = JWTManager()


def init(app: Flask):
    # JWT加密密鑰
    app.config['JWT_SECRET_KEY'] = 'my-sectet'
    jwt.init_app(app)

總入口: run.py

# -*- coding: utf-8 -*-
import DemoApp

# 創建應用
app = DemoApp.create_app()


def main():
    # 運行在8848端口上並接受所有地址的請求
    app.run(host='0.0.0.0', port=8848)


if __name__ == '__main__':
    main()

到此爲止,我們項目依賴關係如下: run.py依賴於DemoApp模塊,DemoApp模塊依賴於多個簡單封裝的Flask插件模塊和若干業務邏輯模塊。

項目結構概覽

    |-- run.py                             // 總入口
    |-- DemoApp                            // WebApi程序
        |-- controllers                    // Controller模塊
            |-- DomoController.py
            |-- ...
            |-- __init__.py
        |-- models                        // 業務邏輯模塊
            |-- db_models                 // 數據庫實體類模塊
            |-- dto_models                // 數據傳輸實體模塊
            |-- ...
            |-- __init__.py
        |-- jwt                          // JWT插件模塊
        |-- log                          // 日誌模塊
        |-- swagger                      // Swagger在線Api文檔模塊
        |-- config                       // 程序相關配置模塊
        |-- __init__.py

DemoApp的Github地址會有的,待我整理一番再放上來。

下節內容

下一節將針對以上提到的Flask插件進行踩坑記錄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章