day98:MoFang:服務端專案搭建

Poke發表於2020-11-26

目錄

1.準備工作

2.建立專案啟動檔案manage.py

3.構建全域性初始化函式並在函式內建立app應用物件

4.通過終端指令碼啟動專案

5.專案載入配置

6.資料庫初始化

  1.SQLAlchemy初始化

  2.Redis初始化

  3.session儲存到redis資料庫中

  4.資料遷移初始化

7.日誌初始化

8.藍圖初始化

  1.通過終端命令建立藍圖,並在藍圖中生成view/model/url等檔案

  2.將藍圖註冊到APP應用物件下

  3.註冊路由和檢視之間的關係

  4.自動註冊藍圖下的所有模型

1.準備工作

1.新建專案目錄mofangapi,並建立虛擬環境

mkvirtualenv mofang

2.安裝開發中使用的依賴模組

pip install flask==0.12.4
pip install flask-redis
pip install flask-session
pip install flask-script
pip install flask-mysqldb
pip install flask-sqlalchemy
pip install flask-migrate

接下來,在pycharm中開啟專案目錄mofangapi編寫manage.py啟動專案的檔案

2.建立專案啟動檔案manage.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

if __name__ == '__main__':
    app.run()

manage.py終不能存放大量的開發程式碼, 在開發中應該體現的是一種分工精神,所以我們可以把flask中各種功能程式碼進行分類分檔案儲存.

現在專案的目錄結構如下所示:

專案根目錄/
├── application/            # 專案主要邏輯程式碼儲存目錄
|   ├── settings/           # 專案配置儲存目錄
│   │   ├ dev.py            # 開發階段的配置檔案
│   │   ├ prod.py           # 生產階段的配置檔案
|   |   ├ __init__.py       # 專案公共配置檔案
│   ├── __init__.py         # 專案初始化檔案
├── manage.py               # 專案的終端管理指令碼檔案

3.構建全域性初始化函式並在函式內建立app應用物件

1.把引導整個專案啟動的全域性初始化程式碼,儲存到application/__init__py,程式碼:

from flask import Flask

def init_app():
    """全域性初始化"""
    app = Flask(__name__) # 建立APP應用物件
    return app

2.在manage.py,中呼叫初始化函式,建立app應用物件,程式碼:

from application import init_app

app = init_app() # 建立app應用物件

@app.route('/')
def index():
    return 'index'

if __name__ == '__main__':
    app.run()

4.通過終端指令碼啟動專案

applicatiion/__init__py,程式碼:

from flask import Flask
from flask_script import Manager

manager = Manager() # 引入終端指令碼管理物件 ***

def init_app():
    """全域性初始化"""
    
    # 建立app應用物件
    app = Flask(__name__)

    # 初始化終端指令碼工具 ***
    manager.app = app

    return manager

manage.py的app改為manage,程式碼:

from application import init_app

manage = init_app()

@manage.app.route('/')
def index():
    return 'index'

if __name__ == '__main__':
    manage.run()

執行專案的方式就要修改如下:

此時我們就可以通過如下指令去執行專案了

python manage.py runserver -h0.0.0.0 -p5000

5.專案載入配置

1.在application/utils/config.py中準備載入配置的函式程式碼:

from importlib import import_module
def load_config(config_path):
    """自動載入配置"""
    module = import_module(config_path)
    name = config_path.split(".")[-1]
    if name == "settings":
        return module.InitConfig
    else:
        return module.Config

2.編寫專案預設配置檔案, application/settings/__init__.py程式碼:

class InitConfig():
    """專案預設初始化配置"""
    DEBUG = True

當然, 專案開發過程完成以後肯定會專案上線,所以針對配置檔案,我們可以準備不同環境下的配置

application/settings/dev.py,程式碼:

from . import InitConfig
class Config(InitConfig):
    """專案開發環境下的配置"""
    DEBUG = True

application/settings/prod.py,程式碼:

from . import InitConfig
class Config(InitConfig):
    """專案運營環境下的配置"""
    DEBUG = False

3.在專案引導檔案application/__init__py中載入配置,程式碼:

from flask import Flask
from flask_script import Manager
from application.utils.config import load_config
manager = Manager()

def init_app(config_path):
    """全域性初始化"""
    # 建立app應用物件
    app = Flask(__name__)
    
    # 設定專案根目錄
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    # 載入配置 ****
    Config = load_config(config_path) # 呼叫utils裡自己已經寫好的load_config方法
    app.config.from_object(Config) # 將配置類註冊到APP上

    # 初始化終端指令碼工具
    manager.app = app

    return manager

4.在建立app物件的專案啟動檔案manage.py中,設定配置

from application import init_app

manage = init_app("application.settings.dev") # 設定預設專案使用的配置檔案是dev.py

@manage.app.route('/')
def index():
    return 'index'

if __name__ == '__main__':
    manage.run()

6.資料庫初始化

1.SQLAlchemy初始化

1.預設專案配置檔案中增加配置選項,application/settings/__init__.py,程式碼:

class InitConfig():
    """專案預設初始化配置"""
    # 除錯模式
    DEBUG = True

    # 資料庫相關配置
    SQLALCHEMY_DATABASE_URI = ""
    # 動態追蹤修改設定
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True

2.開發配置dev.py中,配置資料庫連線資訊,程式碼:

from . import InitConfig
class Config(InitConfig):
    """專案開發環境下的配置"""
    DEBUG = True
    # 資料庫
    SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
    SQLALCHEMY_ECHO = True

3.在mysql終端下, 建立資料庫使用者,命令如下:

create database mofang charset=utf8mb4;
# 針對當前資料庫配置賬戶資訊
create user mofang_user identified by 'mofang';
grant all privileges on mofang.* to 'mofang_user'@'%';
flush privileges;

4.在專案全域性引導檔案中,對資料庫功能進行初始化,application/__init__.py,程式碼:

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from application.utils.config import load_config

# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件 ***
db = SQLAlchemy()

def init_app(config_path):
    """全域性初始化"""
    
    # 建立app應用物件
    app = Flask(__name__)
    # 專案根目錄
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    # 載入配置
    Config = load_config(config_path)
    app.config.from_object(Config)

    # 資料庫初始化 ***
    db.init_app(app)

    # 初始化終端指令碼工具
    manager.app = app

    return manager

2.Redis初始化

1.預設配置檔案,application/settings/__init__py,程式碼:

class InitConfig():
    """專案預設初始化配置"""
    # 除錯模式
    DEBUG = True

    # 資料庫相關配置
    SQLALCHEMY_DATABASE_URI = ""
    # 動態追蹤修改設定
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True
    # Redis
    REDIS_URL = "redis://@127.0.0.1:6379/0"

2.在全域性引導檔案中, 對redis進行初始化,applicaiton/__init__.py,程式碼:

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis

from application.utils.config import load_config

# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件
db = SQLAlchemy()

# redis連結物件 ***
redis = FlaskRedis()

def init_app(config_path):
    """全域性初始化"""
# 建立app應用物件 app = Flask(__name__) # 專案根目錄 app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 載入配置 Config = load_config(config_path) app.config.from_object(Config) # 資料庫初始化 db.init_app(app) redis.init_app(app) # redis資料庫初始化 *** # 初始化終端指令碼工具 manager.app = app return manager

3.session儲存到redis資料庫中

1.因為需要單獨設定一個資料庫存放session,所以我們再次單獨配置一個關於session載入配置的函式init_session,

application/utils/session.py,程式碼:

from redis import Redis
def init_session(app):
    host = app.config.get("SESSION_REDIS_HOST","127.0.0.1")
    port = app.config.get("SESSION_REDIS_PORT",6379)
    db = app.config.get("SESSION_REDIS_DB",0)
    print(db)
    app.config["SESSION_REDIS"] = Redis(host=host,port=port,db=db)

2.預設配置檔案application/settings/__init__.py中, 新增配置項:

class InitConfig():
    """專案預設初始化配置"""
    # 除錯模式
    DEBUG = True

    # 資料庫相關配置
    SQLALCHEMY_DATABASE_URI = ""
    # 動態追蹤修改設定
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True
    # Redis
    REDIS_URL = ""

    # 設定金鑰,可以通過 base64.b64encode(os.urandom(48)) 來生成一個指定長度的隨機字串 ***
    SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"

    '''session儲存配置''' ***
    # session儲存方式配置 ***
    SESSION_TYPE = "redis"
    # 如果設定session的生命週期是否是會話期, 為True,則關閉瀏覽器session就失效 ***
    SESSION_PERMANENT = False
    # 設定session_id在瀏覽器中的cookie有效期 ***
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,單位是秒 ***
    # 是否對傳送到瀏覽器上session的cookie值進行加密 ***
    SESSION_USE_SIGNER = True
    # 儲存到redis的session數的名稱字首 ***
    SESSION_KEY_PREFIX = "session:"
    # session儲存資料到redis時啟用的連結物件 ***
    SESSION_REDIS = None   # 用於連線redis的配置 ***

    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 0

3.在本地開發配置中,設定session儲存指定的redis庫中,application/settings/dev.py,程式碼:

from . import InitConfig
class Config(InitConfig):
    """專案開發環境下的配置"""
    DEBUG = True
    # 資料庫
    SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
    SQLALCHEMY_ECHO = True

    # redis ***
    REDIS_URL = "redis://@127.0.0.1:6379/0" # 0號redis庫用來存redis快取

    # session儲存配置 ***
    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1 # 1號redis庫用來存session

4.在專案全域性引導檔案application/__init__.py中對session儲存進行初始化,程式碼:

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session

from application.utils.config import load_config
from application.utils.session import init_session
# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件
db = SQLAlchemy()

# redis連結物件
redis = FlaskRedis()

# Session儲存物件 ***
session_store = Session()

def init_app(config_path):
    """全域性初始化"""
    # 建立app應用物件
    app = Flask(__name__)
    # 專案根目錄
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    # 載入配置
    Config = load_config(config_path)
    app.config.from_object(Config)

    # 資料庫初始化
    db.init_app(app)
    redis.init_app(app)

    # session儲存初始化 ***
    init_session(app) # 載入session配置 
    session_store.init_app(app) # session儲存初始化
    
    # 初始化終端指令碼工具
    manager.app = app

    return manager

4.資料遷移初始化

1.專案全域性引導檔案application/__init__py,程式碼:

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session
from flask_migrate import Migrate,MigrateCommand # ***

from application.utils.config import load_config
from application.utils.session import init_session

# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件
db = SQLAlchemy()

# redis連結物件
redis = FlaskRedis()

# Session儲存物件
session_store = Session()

# 資料遷移例項物件 ***
migrate = Migrate()

def init_app(config_path):
    """全域性初始化"""
    # 建立app應用物件
    app = Flask(__name__)
    # 專案根目錄
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    # 載入配置
    Config = load_config(config_path)
    app.config.from_object(Config)

    # 資料庫初始化 
    db.init_app(app)
    redis.init_app(app)

    # session儲存初始化
    init_session(app)
    session_store.init_app(app)

    # 資料遷移初始化 ***
    migrate.init_app(app,db)
    # 新增資料遷移的命令到終端指令碼工具中 ***
    manager.add_command('db', MigrateCommand)

    # 初始化終端指令碼工具
    manager.app = app

    return manager

完成上面的專案構建步驟以後,此時目錄結構如下:

專案根目錄/
├── docs/                   # 專案開發文件/介面等備份資料儲存目錄
├── logs/                   # 專案日誌儲存目錄
├── application/            # 專案主要邏輯程式碼儲存目錄
|   ├── settings/           # 專案配置儲存目錄
│   │   ├ dev.py            # 開發階段的配置檔案
│   │   ├ prod.py           # 生產階段的配置檔案
|   |   ├ __init__.py       # 專案公共配置檔案
|   ├── utils/              # 工具函式庫/類庫
│   │   ├ session.py        # session相關的輔助函式
│   │   ├ config.py         # 配置相關的輔助函式
│   ├── __init__.py         # 專案初始化檔案
└── manage.py               # 專案的終端管理指令碼檔案

7.日誌初始化

flask中沒有內建的日誌功能,我們在使用的時候, 一般日誌如果不是核心重點,則通過由python內建的logging模組進行配置整合使用即可, 如果專案中日誌發揮作用比較重要, 則一般安裝部署 ELK日誌分析系統.

1.日誌的等級

FATAL/CRITICAL = 致命的,危險的
ERROR = 錯誤
WARNING = 警告
INFO = 資訊
DEBUG = 除錯

2.構建日誌模組

1.把日誌初始化相關的程式碼封裝成一個函式,application/utils/logger.py,程式碼:

import logging
from logging.handlers import RotatingFileHandler

class Log():
    """日誌模組"""
    
    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

    def init_app(self,app):
        self.app = app
        return self.setup()

    def setup(self):
        """安裝日誌功能到flask中"""
        # 設定日誌的記錄等級
        logging.basicConfig(level=self.app.config.get("LOG_LEVEL"))  # 除錯debug級

        # 建立日誌記錄器,指明日誌儲存的路徑、每個日誌檔案的最大大小、儲存的日誌檔案個數上限
        file_log_handler = RotatingFileHandler(
            self.app.BASE_DIR+self.app.config.get("LOG_DIR"),
            maxBytes=self.app.config.get("LOG_MAX_BYTES"),
            backupCount=self.app.config.get("LOG_BACKPU_COUNT")
        )

        # 建立日誌記錄的格式 日誌等級 輸入日誌資訊的檔名 行數 日誌資訊
        formatter = logging.Formatter('%(name)s: %(levelname)s %(asctime)s %(filename)s:%(lineno)d %(message)s')
        # 為剛建立的日誌記錄器設定日誌記錄格式
        file_log_handler.setFormatter(formatter)

        # 為全域性的日誌工具物件(flaskapp使用的)新增日誌記錄器
        logging.getLogger(self.app.config.get("LOG_NAME")).addHandler(file_log_handler)
        # 返回日誌器物件提供給業務開發
        logger = logging.getLogger(self.app.config.get("LOG_NAME"))
        return logger

2.application/settings/__init__.py程式碼:

class InitConfig():
    """專案預設初始化配置"""
    # 除錯模式
    DEBUG = True

    # 資料庫相關配置
    SQLALCHEMY_DATABASE_URI = ""
    # 動態追蹤修改設定
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True
    # Redis
    REDIS_URL = ""

    # 設定金鑰,可以通過 base64.b64encode(os.urandom(48)) 來生成一個指定長度的隨機字串
    SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"

    # session儲存配置
    # session儲存方式配置
    SESSION_TYPE = "redis"
    # 如果設定session的生命週期是否是會話期, 為True,則關閉瀏覽器session就失效
    SESSION_PERMANENT = False
    # 設定session_id在瀏覽器中的cookie有效期
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,單位是秒
    # 是否對傳送到瀏覽器上session的cookie值進行加密
    SESSION_USE_SIGNER = True
    # 儲存到redis的session數的名稱字首
    SESSION_KEY_PREFIX = "session:"
    # session儲存資料到redis時啟用的連結物件
    SESSION_REDIS = None   # 用於連線redis的配置

    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1

    # 調整json資料轉換中文的配置
    JSON_AS_ASCII=False

    # 日誌相關配置 ***
    LOG_LEVEL        = "INFO"              # 日誌輸出到檔案中的最低等級
    LOG_DIR          = "logs/0.log"        # 日誌儲存目錄
    LOG_MAX_BYTES    = 300 * 1024 * 1024   # 單個日誌檔案的儲存上限[單位: b]
    LOG_BACKPU_COUNT = 20                  # 日誌檔案的最大備份數量
    LOG_NAME         = "flask"             # 日誌器的名字

3.開發環境配置檔案dev.py中配置具體的日誌相關資訊,程式碼:

from . import InitConfig
class Config(InitConfig):
    """專案開發環境下的配置"""
    DEBUG = True
    # 資料庫
    SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
    SQLALCHEMY_ECHO = True

    # redis
    REDIS_URL = "redis://@127.0.0.1:6379/0"

    # session儲存配置
    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1

    # 日誌配置 ***
    LOG_LEVEL        = "DEBUG"             # 日誌輸出到檔案中的最低等級
    LOG_DIR          = "/logs/mofang.log"  # 日誌儲存目錄
    LOG_MAX_BYTES    = 300 * 1024 * 1024   # 單個日誌檔案的儲存上限[單位: b]
    LOG_BACKPU_COUNT = 20                  # 日誌檔案的最大備份數量
    LOG_NAME = "mofang"                    # 日誌器名稱

4.在 application/__init__.py檔案中的init_app 方法中呼叫日誌初始化。

import os,logging

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session
from flask_migrate import Migrate,MigrateCommand

from application.utils.config import load_config
from application.utils.session import init_session
from application.utils.logger import Log
# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件
db = SQLAlchemy()

# redis連結物件
redis = FlaskRedis()

# Session儲存物件
session_store = Session()

# 資料遷移例項物件
migrate = Migrate()

# 日誌物件 ***
log = Log()

def init_app(config_path):
    """全域性初始化"""
    # 建立app應用物件
    app = Flask(__name__)
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 載入配置
    Config = load_config(config_path)
    app.config.from_object(Config)

    # 資料庫初始化
    db.init_app(app)
    redis.init_app(app)

    # session儲存初始化
    init_session(app)
    session_store.init_app(app)

    # 資料遷移初始化
    migrate.init_app(app,db)
    # 新增資料遷移的命令到終端指令碼工具中
    manager.add_command('db', MigrateCommand)

    # 日誌初始化 ***
    app.log = log.init_app(app)

    # 初始化終端指令碼工具
    manager.app = app

    return manager

新增日誌的專案目錄結構如下所示

├── application
│   ├── __init__.py
│   ├── settings
│   │   ├── dev.py
│   │   ├── __init__.py
│   │   ├── prod.py
│   └── utils
│       ├── config.py
│       ├── __init__.py
│       ├── logger.py      # 日誌相關模組程式碼庫
│       └── session.py
├── docs
├── logs                    # 日誌檔案儲存目錄
│   └── mofang.log
└── manage.py

經過上面的改造,我們接下來就可以開始建立藍圖了。

8.藍圖初始化

1.通過終端命令建立藍圖,並在藍圖中生成view/model/url等檔案

1.在application下建立apps目錄,apps以後專門用於儲存每一個專案的藍圖,並在apps建立home藍圖目錄,並在__init__.py檔案中建立藍圖物件

通過自定義終端命令, 建立一個自動生成藍圖目錄的命令.application/utils/commands.py,程式碼:

from flask_script import Command, Option

class BlueprintCommand(Command):
    """藍圖生成命令"""
    name = "blue"
    option_list = [
        Option('--name', '-n', dest='name'),
    ]
    def run(self, name):
        # 生成藍圖名稱物件的目錄
        os.mkdir(name)
        open("%s/__init__.py" % name, "w")
        open("%s/views.py" % name, "w")
        open("%s/models.py" % name, "w")
        with open("%s/urls.py" % name, "w") as f:
            content = """from . import views
from application.utils import path
urlpatterns = [

]"""
            f.write(content)
        print("藍圖%s建立完成...." % name)

2.上面的命令就可以幫我們完成專案中生成藍圖的功能,接下來我們就可以直接把命令註冊到manage物件中就可以使用了.

但是, 我們往後的開發中肯定還會繼續的需要進行自定義終端命令,所以我們宣告一個load_command的函式,讓自動幫我們完成載入註冊自定義終端命令的過程.

application/utils/commands.py,程式碼:

 

import os
from importlib import import_module
from flask_script import Command, Option
import inspect

def load_command(manager,command_path=None):
    """自動載入自定義終端命令"""
    if command_path is None:
        command_path = "application.utils.commands"

    module = import_module(command_path)
    class_list = inspect.getmembers(module,inspect.isclass)
    for class_item in class_list:
        if issubclass(class_item[1],Command) and class_item[0] != "Command":
            manager.add_command(class_item[1].name,class_item[1])

class BlueprintCommand(Command):
    """藍圖生成命令"""
    name = "blue"
    option_list = [
        Option('--name', '-n', dest='name'),
    ]
    def run(self, name):
        # 生成藍圖名稱物件的目錄
        os.mkdir(name)
        open("%s/__init__.py" % name, "w")
        open("%s/views.py" % name, "w")
        open("%s/models.py" % name, "w")
        with open("%s/urls.py" % name, "w") as f:
            content = """from . import views
from application.utils import path
urlpatterns = [

]"""
            f.write(content)
        print("藍圖%s建立完成...." % name)

3.在專案全域性引導檔案application/__init__.py中, 呼叫load_command函式註冊命令

import os,logging

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session
from flask_migrate import Migrate,MigrateCommand

from application.utils.config import load_config
from application.utils.session import init_session
from application.utils.logger import Log
from application.utils.commands import load_command
# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件
db = SQLAlchemy()

# redis連結物件
redis = FlaskRedis()

# Session儲存物件
session_store = Session()

# 資料遷移例項物件
migrate = Migrate()

# 日誌物件
log = Log()

def init_app(config_path):
    """全域性初始化"""
    # 建立app應用物件
    app = Flask(__name__)
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 載入配置
    Config = load_config(config_path)
    app.config.from_object(Config)

    # 資料庫初始化
    db.init_app(app)
    redis.init_app(app)

    # session儲存初始化
    init_session(app)
    session_store.init_app(app)

    # 資料遷移初始化
    migrate.init_app(app,db)
    # 新增資料遷移的命令到終端指令碼工具中
    manager.add_command('db', MigrateCommand)

    # 日誌初始化
    app.log = log.init_app(app)

    # 初始化終端指令碼工具
    manager.app = app

    # 註冊自定義命令 ***
    load_command(manager)

    return manager

4.接下來就可以在終端下,通過命令生成藍圖目錄了.

命令:

cd application/apps
python ../../manage.py blue -nhome

效果:

2.將藍圖註冊到APP應用物件下

有了藍圖以後,接下來我們就可以檢視程式碼,模型程式碼,路由程式碼等儲存到藍圖目錄下了,但是我們需要把藍圖註冊到app應用物件下.所以我們註冊藍圖這塊程式碼也可以封裝到一個函式中.讓程式自動識別並註冊.

專案中可以有多個藍圖,但是有些藍圖可能並不能提供給客戶端訪問,所以我們需要在配置檔案中宣告一個藍圖註冊列表, 在init_blueprint函式中只註冊配置列表的藍圖

1.application/settings/__init__.py,程式碼:

class InitConfig():
    """專案預設初始化配置"""
    # 除錯模式
    DEBUG = True

    # 資料庫相關配置
    SQLALCHEMY_DATABASE_URI = ""
    # 動態追蹤修改設定
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True
    # Redis
    REDIS_URL = ""

    # 設定金鑰,可以通過 base64.b64encode(os.urandom(48)) 來生成一個指定長度的隨機字串
    SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"

    # session儲存配置
    # session儲存方式配置
    SESSION_TYPE = "redis"
    # 如果設定session的生命週期是否是會話期, 為True,則關閉瀏覽器session就失效
    SESSION_PERMANENT = False
    # 設定session_id在瀏覽器中的cookie有效期
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,單位是秒
    # 是否對傳送到瀏覽器上session的cookie值進行加密
    SESSION_USE_SIGNER = True
    # 儲存到redis的session數的名稱字首
    SESSION_KEY_PREFIX = "session:"
    # session儲存資料到redis時啟用的連結物件
    SESSION_REDIS = None   # 用於連線redis的配置

    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1

    # 調整json資料轉換中文的配置
    JSON_AS_ASCII=False

    # 日誌相關配置
    LOG_LEVEL        = "INFO"              # 日誌輸出到檔案中的最低等級
    LOG_DIR          = "logs/0.log"        # 日誌儲存目錄
    LOG_MAX_BYTES    = 300 * 1024 * 1024   # 單個日誌檔案的儲存上限[單位: b]
    LOG_BACKPU_COUNT = 20                  # 日誌檔案的最大備份數量
    LOG_NAME         = "flask"             # 日誌器的名字

    # 藍圖註冊列表 ***
    INSTALLED_APPS = [

    ]

application/settings/dev.py,程式碼:

from . import InitConfig
class Config(InitConfig):
    """專案開發環境下的配置"""
    DEBUG = True
    # 資料庫
    SQLALCHEMY_DATABASE_URI = "mysql://mofang_user:mofang@127.0.0.1:3306/mofang?charset=utf8mb4"
    SQLALCHEMY_ECHO = True

    # redis
    REDIS_URL = "redis://@127.0.0.1:6379/0"

    # session儲存配置
    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1

    # 日誌配置
    LOG_LEVEL        = "DEBUG"             # 日誌輸出到檔案中的最低等級
    LOG_DIR          = "/logs/mofang.log"  # 日誌儲存目錄
    LOG_MAX_BYTES    = 300 * 1024 * 1024   # 單個日誌檔案的儲存上限[單位: b]
    LOG_BACKPU_COUNT = 20                  # 日誌檔案的最大備份數量
    LOG_NAME = "mofang"                    # 日誌器名稱

    # 註冊藍圖  ***
    INSTALLED_APPS = [ 
        "application.apps.home",
    ]

2.在init_blueprint函式中,針對註冊的藍圖列表註冊到app應用物件裡面,

application/utils/__init__.py,程式碼:

def init_blueprint(app):
    """自動註冊藍圖"""
    blueprint_path_list = app.config.get("INSTALLED_APPS")
    for blueprint_path in blueprint_path_list:
        blueprint_name = blueprint_path.split(".")[-1]
        # 自動建立藍圖物件
        blueprint = Blueprint(blueprint_name,blueprint_path)

        # 註冊藍圖物件到app應用物件中
        app.register_blueprint(blueprint,url_prefix="")

3.專案全域性引導檔案中, 呼叫init_blueprint方法, 自動註冊藍圖.application/__init__.py,程式碼:

import os,logging

from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session
from flask_migrate import Migrate,MigrateCommand

from application.utils import init_blueprint
from application.utils.config import load_config
from application.utils.session import init_session
from application.utils.logger import Log
from application.utils.commands import load_command
# 建立終端指令碼管理物件
manager = Manager()

# 建立資料庫連結物件
db = SQLAlchemy()

# redis連結物件
redis = FlaskRedis()

# Session儲存物件
session_store = Session()

# 資料遷移例項物件
migrate = Migrate()

# 日誌物件
log = Log()

def init_app(config_path):
    """全域性初始化"""
    # 建立app應用物件
    app = Flask(__name__)
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 載入配置
    Config = load_config(config_path)
    app.config.from_object(Config)

    # 資料庫初始化
    db.init_app(app)
    redis.init_app(app)

    # session儲存初始化
    init_session(app)
    session_store.init_app(app)

    # 資料遷移初始化
    migrate.init_app(app,db)
    # 新增資料遷移的命令到終端指令碼工具中
    manager.add_command('db', MigrateCommand)

    # 日誌初始化
    app.log = log.init_app(app)

    # 藍圖註冊 ***
    init_blueprint(app)

    # 初始化終端指令碼工具
    manager.app = app

    # 註冊自定義命令
    load_command(manager)

    return manager

3.註冊路由和檢視之間的關係

1.註冊子路由和檢視之間的關係

註冊了藍圖物件以後,藍圖下面的檢視方法和檢視對應的路由關係也要進行註冊!

所以, 在藍圖home下面的urls.py檔案中,通過path方法把url地址和檢視方法進行處理成字典,然後把字典作為成員返回到變數urlpatterns列表中.

1.application/utils/__init__.py,生成path函式,程式碼:

from flask import Blueprint
from importlib import import_module
def path(rule,func_view):
    # 把藍圖下檢視和路由之間的對映關係處理成字典結構,方便後面註冊藍圖的時候,直接傳參
    return {"rule":rule,"view_func":func_view}

2.在藍圖下的urls.py中,註冊檢視和路由的關係,home/urls.py,程式碼:

from . import views
from application.utils import path
urlpatterns = [
    path("/",views.index),
]

檢視程式碼:

def index():
    return 'index'

3.在init_blueprint初始化藍圖的函式中, 生成藍圖物件以後自動載入並註冊藍圖和檢視

application/utils/__init__.py,程式碼:

from flask import Blueprint
from importlib import import_module
def path(rule,func_view):
    # 把藍圖下檢視和路由之間的對映關係處理成字典結構,方便後面註冊藍圖的時候,直接傳參
    return {"rule":rule,"view_func":func_view}

def init_blueprint(app):
    """自動註冊藍圖"""
    blueprint_path_list = app.config.get("INSTALLED_APPS")
    for blueprint_path in blueprint_path_list:
        blueprint_name = blueprint_path.split(".")[-1]
        # 自動建立藍圖物件
        blueprint = Blueprint(blueprint_name,blueprint_path)
        # 藍圖自動註冊和繫結檢視和子路由
        url_module = import_module(blueprint_path+".urls") # 載入藍圖下的子路由檔案
        for url in url_module.urlpatterns: # 遍歷子路由中的所有路由關係
            blueprint.add_url_rule(**url)  # 註冊到藍圖下
        # 註冊藍圖物件到app應用物件中
        app.register_blueprint(blueprint,url_prefix="")

2.註冊總路由和藍圖之間的關係

4.此時, 執行專案,就允許藍圖中檢視通過url地址提供給客戶端訪問了.

上面藍圖註冊到app時, 沒有設定url_prefix路由字首, 接下來我們可以單獨設定一個總路由application/urls.py,進行路由字首的設定.

在專案預設配置檔案中,application/settings/__init__.py,新增總路由的配置項

class InitConfig():
    """專案預設初始化配置"""
    # 除錯模式
    DEBUG = True

    # 資料庫相關配置
    SQLALCHEMY_DATABASE_URI = ""
    # 動態追蹤修改設定
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True
    # Redis
    REDIS_URL = ""

    # 設定金鑰,可以通過 base64.b64encode(os.urandom(48)) 來生成一個指定長度的隨機字串
    SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"

    # session儲存配置
    # session儲存方式配置
    SESSION_TYPE = "redis"
    # 如果設定session的生命週期是否是會話期, 為True,則關閉瀏覽器session就失效
    SESSION_PERMANENT = False
    # 設定session_id在瀏覽器中的cookie有效期
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60  # session 的有效期,單位是秒
    # 是否對傳送到瀏覽器上session的cookie值進行加密
    SESSION_USE_SIGNER = True
    # 儲存到redis的session數的名稱字首
    SESSION_KEY_PREFIX = "session:"
    # session儲存資料到redis時啟用的連結物件
    SESSION_REDIS = None   # 用於連線redis的配置

    SESSION_REDIS_HOST = "127.0.0.1"
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 1

    # 調整json資料轉換中文的配置
    JSON_AS_ASCII=False

    # 日誌相關配置
    LOG_LEVEL        = "INFO"              # 日誌輸出到檔案中的最低等級
    LOG_DIR          = "logs/0.log"        # 日誌儲存目錄
    LOG_MAX_BYTES    = 300 * 1024 * 1024   # 單個日誌檔案的儲存上限[單位: b]
    LOG_BACKPU_COUNT = 20                  # 日誌檔案的最大備份數量
    LOG_NAME         = "flask"             # 日誌器的名字

    # 藍圖註冊列表
    INSTALLED_APPS = [

    ]


    # 總路由 ***
    URL_PATH = "application.urls"

5.建立總路由檔案並註冊藍圖和路由字首的關係, application/urls.py,程式碼:

from application.utils import include
urlpatterns = [
    include("","home.urls"),
]

6.接下來,在init_blueprint藍圖初始化函式中新增判斷識別路由字首的程式碼; 同時, 把路由字首和藍圖對映關係的處理程式碼封裝成include方法,方便以後需求變化時可以直接調整.

application/utils/__init__.py,程式碼:

from flask import Blueprint
from importlib import import_module
def path(rule,func_view):
    # 把藍圖下檢視和路由之間的對映關係處理成字典結構,方便後面註冊藍圖的時候,直接傳參
    return {"rule":rule,"view_func":func_view}

def include(url_prefix, blueprint_path):
    """把路由字首和藍圖進行關係對映"""
    return {"url_prefix":url_prefix,"blueprint_path":blueprint_path}

def init_blueprint(app):
    """自動註冊藍圖"""
    blueprint_path_list = app.config.get("INSTALLED_APPS")
    for blueprint_path in blueprint_path_list:
        blueprint_name = blueprint_path.split(".")[-1]
        # 自動建立藍圖物件
        blueprint = Blueprint(blueprint_name,blueprint_path)
        # 藍圖自動註冊和繫結檢視和子路由
        url_module = import_module(blueprint_path+".urls") # 載入藍圖下的子路由檔案
        for url in url_module.urlpatterns: # 遍歷子路由中的所有路由關係
            blueprint.add_url_rule(**url)  # 註冊到藍圖下

        # 讀取總路由檔案
        url_path = app.config.get("URL_PATH")
        urlpatterns = import_module(url_path).urlpatterns  # 載入藍圖下的子路由檔案
        url_prefix = "" # 藍圖路由字首
        for urlpattern in urlpatterns:
            if urlpattern["blueprint_path"] == blueprint_name+".urls":
                url_prefix = urlpattern["url_prefix"]
                break
        # 註冊藍圖物件到app應用物件中,  url_prefix 藍圖的路由字首
        app.register_blueprint(blueprint,url_prefix=url_prefix)

4.自動註冊藍圖下的所有模型

1.在藍圖下的models.py中宣告模型,例如:

from application import db
class User(db.Model):
    __tablename__ = "mf_user"
    id = db.Column(db.Integer, primary_key=True, comment="主鍵ID")
    name = db.Column(db.String(255), unique=True, comment="賬戶名")
    password = db.Column(db.String(255), comment="登入密碼")
    ip_address = db.Column(db.String(255), index=True, comment="登入IP")

    def __repr__(self):
        return self.name

2.然後在終端下執行資料遷移

cd ../..
python manage.py db init
python manage.py db migrate -m "text"

3.上面的命令執行以後, 我們可以發現模型根本被flask進行識別到.所以我們需要把模型註冊到flask專案中.

application/utils/__init__.py,程式碼:

from flask import Blueprint
from importlib import import_module
def path(rule,func_view):
    # 把藍圖下檢視和路由之間的對映關係處理成字典結構,方便後面註冊藍圖的時候,直接傳參
    return {"rule":rule,"view_func":func_view}

def include(url_prefix, blueprint_path):
    """把路由字首和藍圖進行關係對映"""
    return {"url_prefix":url_prefix,"blueprint_path":blueprint_path}

def init_blueprint(app):
    """自動註冊藍圖"""
    blueprint_path_list = app.config.get("INSTALLED_APPS")
    for blueprint_path in blueprint_path_list:
        blueprint_name = blueprint_path.split(".")[-1]
        # 自動建立藍圖物件
        blueprint = Blueprint(blueprint_name,blueprint_path)
        # 藍圖自動註冊和繫結檢視和子路由
        url_module = import_module(blueprint_path+".urls") # 載入藍圖下的子路由檔案
        for url in url_module.urlpatterns: # 遍歷子路由中的所有路由關係
            blueprint.add_url_rule(**url)  # 註冊到藍圖下

        # 讀取總路由檔案
        url_path = app.config.get("URL_PATH")
        urlpatterns = import_module(url_path).urlpatterns  # 載入藍圖下的子路由檔案
        url_prefix = "" # 藍圖路由字首
        for urlpattern in urlpatterns:
            if urlpattern["blueprint_path"] == blueprint_name+".urls":
                url_prefix = urlpattern["url_prefix"]
                break

        # 註冊模型 ***
        import_module(blueprint_path+".models")

        # 註冊藍圖物件到app應用物件中,  url_prefix 藍圖的路由字首
        app.register_blueprint(blueprint,url_prefix=url_prefix)

專案能自動載入總路由和藍圖路由以後的專案目錄結構,如下:

專案根目錄/
├── application/            # 專案主要邏輯程式碼儲存目錄
|   ├── settings/           # 專案配置儲存目錄
│   │   ├ __init__.py       # 專案預設初始化配置檔案
│   │   ├ dev.py            # 開發階段的配置檔案
│   │   └ prod.py           # 生產階段的配置檔案
│   ├── __init__.py         # 專案初始化全域性引導檔案
|   ├── utils/              # 專案工具類庫目錄
│   │   ├ commands.py       # 自定義命令和載入命令的相關函式
│   │   ├ config.py         # 專案配置載入的輔助函式
│   │   ├ session.py        # 專案儲存session相關的函式
│   │   └ logger.py         # 日誌模組
│   ├── apps/               # 儲存專案中所有藍圖的儲存目錄
│   │   ├── home            # 藍圖目錄【這裡是舉例而已】
│   │   │   ├── __init__.py # 藍圖的初始化檔案
│   │   │   ├── urls.py     # 藍圖的子路由檔案
│   │   │   ├── models.py   # 藍圖的模型檔案
│   │   │   └── views.py    # 藍圖的檢視檔案
│   │   ├── __init__.py
│   └── urls.py              # 總路由
├── manage.py               # 專案的終端管理指令碼檔案

 

相關文章