1. 程式人生 > >Flask修煉——資料庫遷移及藍圖!

Flask修煉——資料庫遷移及藍圖!



內容概述:
資料庫遷移、
藍圖、
單元測試。


資料庫遷移

  • 在開發過程中,需要修改資料庫模型,而且還要在修改之後更新資料庫。最直接的方式就是刪除舊錶,但這樣會丟失資料。
  • 更好的解決辦法是使用資料庫遷移框架,它可以追蹤資料庫模式的變化,然後把變動應用到資料庫中。
  • 在Flask中可以使用Flask-Migrate擴充套件,來實現資料遷移。並且整合到Flask-Script中,所有操作通過命令就能完成。
  • 為了匯出資料庫遷移命令,Flask-Migrate提供了一個MigrateCommand類,可以附加到flask-script的manager物件上。

Migrate 遷移

在虛擬環境中安裝 Migrate : pip install flask-Migrate

配置命令

Migrate(app, db) # 使用遷移類將應用和資料庫連線物件儲存起來

manager = Manager(app) # 建立終端命令的物件

manager.add_command(‘db’, MigrateCommand) # 將資料庫遷移命令新增到 manager 中

遷移命令

python xxx.py db init # 遷移初始化(生成遷移所需要資料夾 migrations)

python

xxx.py db migrate -m “initial” # 生成遷移版本檔案

python xxx.py db upgrade # 執行遷移

python xxx.py db history # 檢視歷史版本

python xxx.py db downgrade 版本號 # 回滾到指定版本

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate, MigrateCommand
# MigrateCommand   就是遷移的命令
from flask_script import Manager # 總結遷移的命令 # 1.遷移初始化(生成遷移所需要資料夾 migrateions) python xxx.py db init # 2. 生成遷移版本檔案 python xxx.py db migrate -m'inital' # 3. 執行遷移(向上遷移) python xxx.py db upgrade app = Flask(__name__) app.secret_key = 'asdfasdf' # 配置資料庫 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/migratetest' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) # 使用遷移類將應用和資料庫連線物件儲存起來 Migrate(app, db) # 建立終端命令的物件 manager = Manager(app) # 將資料庫的遷移命令新增到 manager 中 manager.add_command('db', MigrateCommand) # 定義模型Role class Role(db.Model): # 定義表名 __tablename__ = 'roles' # 定義列物件 id = db.Column(db.Integer, primary_key=True) nick_name = db.Column(db.String(64), unique=True) # 標題 title = db.Column(db.String(64)) user = db.relationship('User', backref='role') # repr()方法顯示一個可讀字串, def __repr__(self): return 'Role:'.format(self.name) # 定義使用者 class User(db.Model): __talbe__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) # 設定外來鍵 role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) @app.route('/') def index(): return 'Hello World!' if __name__ == '__main__': manager.run()



藍圖(BluePrint)

簡單來說,Blueprint 是一個儲存操作方法的容器,這些操作在這個Blueprint 被註冊到一個應用之後就可以被呼叫,Flask 可以通過Blueprint來組織URL以及處理請求。

Flask使用Blueprint讓應用實現模組化,在Flask中,Blueprint具有如下屬性:

  • 一個應用可以具有多個Blueprint
  • 可以將一個Blueprint註冊到任何一個未使用的URL下比如 “/”、“/sample”或者子域名
  • 在一個應用中,一個模組可以註冊多次
  • Blueprint可以單獨具有自己的模板、靜態檔案或者其它的通用操作方法,它並不是必須要實現應用的檢視和函式的
  • 在一個應用初始化時,就應該要註冊需要使用的Blueprint

但是一個Blueprint並不是一個完整的應用,它不能獨立於應用執行,而必須要註冊到某一個應用中。

BluePrint 藍圖, 就是把以前在檢視的函式寫到藍圖中去, 相當於對檔案進行模組化管理

# 藍圖使用流程
# 匯入藍圖類
from flask import BluePrint
 
# 初始化藍圖
login_blu = BluePrint('login', __name__)
 
# 使用藍圖註冊 url
@login_blu.route('/login/list')
 
# 註冊藍圖
app.register_blueprint(login_blu)

注意:

初始化藍圖的時候,需要賦值訪問路徑;

註冊藍圖時,可以指定一個 urlprefix 關鍵字引數(這個引數預設是/),在應用最終的路由表 url_map 中,在藍圖上註冊的路由 URL 自動被加上了這個字首,這個可以保證在多個藍圖中使用相同的 URL 規則而不會最終引起衝突,只有在註冊藍圖時將不同的藍圖掛接到不同的自路徑即可。

MVTB 模型:

M:資料庫

V:檢視

T:template

B:BluePrint 藍圖


  • 主檔案 main.py
from flask import Flask
from order import order_blu
from cart import cart_blu

app = Flask(__name__)
# 把藍圖註冊到 app 上
app.register_blueprint(order_blu)
app.register_blueprint(cart_blu)


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


""" 一下程式碼抽取到 order.py 中
# 訂單列表
@app.route('/order/list')
def order_list():
    return 'order_list'
"""


@app.route('/usr/info')
def user_info():
    return 'user_info'


""" 以下程式碼拷貝到 cart 模組裡面
@app.route('/cart/list')
def cart_list():
    return 'cart_list'
"""

if __name__ == '__main__':
    print(app.url_map)  # url_map 中儲存當前函式中所有的路由和檢視的對應關係
    app.run(debug=True)

  • 包檔案 __init__.py
from flask import Blueprint

cart_blu = Blueprint('cart', __name__, static_folder="static", template_folder='templates',
                     url_prefix='/cart')

from .views import *

  • 包檔案 views.py
from flask import render_template

from . import cart_blu


@cart_blu.route('/list')
def cart_list():
    return render_template('cart.html')



單元測試

什麼是單元測試:當代碼寫完之後,檢查程式碼是否符合要求,可以編寫測試程式碼,模擬程式執行的過程,檢驗程式碼功能是否符合預期。

在 Web 開發過程中,單元測試實際上就是一些 “斷言 (assert)”程式碼。

斷言就是判斷一個函式或物件的一個方法所產生的結果是否符合你期望的那個結果。

python 中的 assert 斷言是宣告布林值為真的判定,如果表示式為假會發生異常。


常見斷言方法
assertEqual     # 如果兩個值相等,則pass
assertNotEqual  # 如果兩個值不相等,則pass
assertTrue      # 判斷bool值為True,則pass
assertFalse     # 判斷bool值為False,則pass
assertIsNone    # 不存在,則pass
assertIsNotNone # 存在,則pass

測試類要繼承自 unittest.TestCase

在測試類中定義測試方法

單元測試要以 test 開頭

進行測試

# 對資料庫進行測試新增和刪除
import unittest
from demo3_bookDemo import app, db, Author


class DataBaseTestCase(unittest.TestCase):

    # 因為是測試資料的新增和刪除, 所以需要單獨為測試建立一個 database
    # 該方法會首先執行,相當於做測試前的準備工作
    def setUp(self):
        app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:[email protected]:3306/booktest_unittest"
        app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

        db.create_all()

    # 該方法會在測試程式碼執行完後執行,相當於做測試後的掃尾工作
    def tearDown(self):
        db.session.remove()
        db.drop_all()
    
    # 測試程式碼
    def test_add_and_delete_author(self):
        author = Author(name='哈賽')
        db.session.add(author)
        db.session.commit()

        # 查詢
        author = Author.query.filter(Author.name == '哈賽').first()
        self.assertIsNotNone(author)

        import time
        time.sleep(10)

        # 刪除
        db.session.delete(author)
        db.session.commit()