day96:flask:flask-migrate&flask-session&藍圖Blueprint&藍圖的執行機制

Poke發表於2020-11-24

目錄

1.flask-migrate

2.flask-session

3.藍圖:Blueprint

4.藍圖的執行機制

1.資料庫遷移:flask-migrate

1.Flask的資料庫遷移

  • 在開發過程中,需要修改資料庫模型,而且還要在修改之後更新資料庫。最直接的方式就是刪除舊錶,但這樣會丟失資料。

  • 更好的解決辦法是使用資料庫遷移框架,它可以追蹤資料庫模式的變化,然後把變動應用到資料庫中。

  • 在Flask中可以使用Flask-Migrate擴充套件,來實現資料遷移。並且整合到Flask-Script中,所有操作通過命令就能完成。

  • 為了匯出資料庫遷移命令,Flask-Migrate提供了一個MigrateCommand類,可以附加到flask-script的manager物件上。

2.flask-migrate的安裝

pip install flask-migrate

3.在flask程式碼中引入資料庫遷移

from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand # 1.引入Migrate和MigrateCommand
from flask_script import Manager,Command

app = Flask(__name__,template_folder='templates')
app.config.from_object(Config)

manage = Manager(app)

db = SQLAlchemy(app)


# 2.建立migrate物件。第一個引數是Flask的例項,第二個引數是Sqlalchemy資料庫例項
migrate = Migrate(app,db)

# 3.manager是Flask-Script的例項,這條語句在flask-Script中新增一個db命令
manage.add_command('db',MigrateCommand)


achieve = db.Table('tb_achievement',
    db.Column('student_id', db.Integer, db.ForeignKey('tb_student.id')),
    db.Column('course_id', db.Integer, db.ForeignKey('tb_course.id'))
)


class Course(db.Model):
    __tablename__ = 'tb_course'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    teacher_id = db.Column(db.Integer, db.ForeignKey('tb_teacher.id'))
    students = db.relationship('Student', secondary=achieve, backref='courses', lazy='subquery')

    def __repr__(self):
        return 'Course:%s'% self.name

class Student(db.Model):
    __tablename__ = 'tb_student'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(64),unique=True)
    age = db.Column(db.SmallInteger,nullable=False)
    sex = db.Column(db.Boolean,default=1)

    def __repr__(self):
        return 'Student:%s' % self.name

class Teacher(db.Model):
    __tablename__ = 'tb_teacher'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    courses = db.relationship('Course', backref='teacher', lazy='subquery')

    def __repr__(self):
        return 'Teacher:%s' % self.name


@app.route("/")
def index():
    return "ok"

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

4.flask中資料庫遷移常用的命令

1.建立遷移版本倉庫

# 這個命令會建立migrations資料夾,所有遷移檔案都放在裡面。
python main.py db init

2.建立遷移版本倉庫

# 這裡等同於django裡面的 makemigrations,生成遷移版本檔案
python main.py db migrate -m 'initial migration'

3.升級遷移版本庫的版本

python main.py db upgrade 

4.降級遷移版本庫的版本

 

 

python main.py db downgrade

5.回滾到指定版本

python manage.py db downgrade 版本號   # 返回到指定版本號對應的版本

6.檢視資料庫遷移歷史(可檢視資料庫遷移版本號)

python manage.py db history

# 輸出格式:<base> ->  版本號 (head), initial migration

一般資料遷移的步驟是:init-->migrate-->upgrade/downgrade

2.flask-session

flask-session:允許設定session到指定儲存的空間中

安裝命令: https://pythonhosted.org/Flask-Session/

1.flask-session的安裝和配置

pip install flask-Session

使用session之前,必須配置一下配置項:

SECRET_KEY = "*(%#4sxcz(^(#$#8423" # session祕鑰

2.redis儲存session的基本配置

from flask import Flask,session
from flask_redis import FlaskRedis
from flask_session import Session
app = Flask(__name__)
redis = FlaskRedis()
session_store = Session()
class Config():
    # DEBUG除錯模式
    DEBUG = True

    # json多位元組轉unicode編碼
    JSON_AS_ASCII = False

    # 資料庫連結配置
    SECRET_KEY = "*(%#4sxcz(^(#$#8423"

    # 1.session儲存方式為redis
    SESSION_TYPE = "redis"

    # 2.session儲存資料到redis時啟用的連結物件
    SESSION_REDIS = redis

    # 3.如果設定session的生命週期是否是會話期, 為True,則關閉瀏覽器session就失效
    SESSION_PERMANENT = True

    # 4.是否對傳送到瀏覽器上session的cookie值進行加密
    SESSION_USE_SIGNER = True

    # 5.儲存到redis的session數的名稱字首
    SESSION_KEY_PREFIX = "session:"

    # 6.redis的連結配置
    REDIS_URL = "redis://localhost:6379/1"


app.config.from_object(Config) # 將Config類註冊到app上
redis.init_app(app)  # 將flask-redis物件掛載到app上
session_store.init_app(app) # 將flask-session物件掛載到app上


@app.route("/")
def index():
    session["username"] = "xiaoming"
    return "Ok"

@app.route("/get_session")
def get_session():
    print( session["username"] )
    return "ok"

@app.route("/redis1")
def set_redis():
    # redis給集合資料型別/雜湊資料型別設定值
    redis.set("username","xiaohuihui")
    redis.hset("brother","zhangfei","17")
    return "ok"

@app.route("/redis2")
def get_redis():
    user = redis.get("username").decode()

    brother = redis.hgetall("brother")
    print(brother["zhangfei".encode()].decode())

    return "ok"

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

執行程式,訪問127.0.0.1:5000,即可將session值儲存到redis中

如圖所示:

3.SQLAlchemy儲存session的基本配置

from flask import Flask,session
from flask_redis import FlaskRedis
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
db = SQLAlchemy()
redis = FlaskRedis()
session_store = Session()

class Config():

    ......
    '''資料庫連結配置'''
    # SQLALCHEMY_DATABASE_URI = "mysql://賬號:密碼@IP/資料庫名?編碼"
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4"
    
    # 動態追蹤修改設定,如未設定只會提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO = True

    '''資料庫儲存session'''
    SESSION_TYPE = 'sqlalchemy'  # session型別為sqlalchemy
    SESSION_SQLALCHEMY = db  # SQLAlchemy物件
    SESSION_SQLALCHEMY_TABLE = 'tb_session'  # session要儲存的表名稱
    SESSION_PERMANENT = True  # 如果設定為True,則關閉瀏覽器session就失效。
    SESSION_USE_SIGNER = False  # 是否對傳送到瀏覽器上session的cookie值進行加密
    SESSION_KEY_PREFIX = 'session:'  # 儲存到session中的值的字首

db.init_app(app)
app.config.from_object(Config)
redis.init_app(app)
session_store.init_app(app)

@app.route("/")
def index():
    session["username"] = "xiaohui"
    return "Ok"

@app.route("/get_session")
def get_session():
    return session["username"]

if __name__ == '__main__':
    # with app.app_context():
    #     db.create_all()
    app.run()

執行程式,訪問127.0.0.1:5000,即可將session值儲存到mysql中

如圖所示:

3.藍圖:Blueprint

1.藍圖:模組化

隨著flask程式越來越複雜,我們需要對程式進行模組化的處理,之前學習過python的模組化管理,於是針對一個簡單的flask程式進行模組化處理

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

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

  • 一個專案可以具有多個Blueprint

  • 可以將一個Blueprint註冊到任何一個未使用的URL下比如 “/”、“/sample”或者子域名

  • 在一個應用中,一個模組可以註冊多次

  • Blueprint可以單獨具有自己的模板、靜態檔案或者其它的通用操作方法,它並不是必須要實現應用的檢視和函式的

  • 在一個應用初始化時,就應該要註冊需要使用的Blueprint

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

Blueprint物件用起來和一個應用/Flask物件差不多,最大的區別在於一個 藍圖物件沒有辦法獨立執行,必須將它註冊到一個應用物件上才能生效.

2.簡單使用藍圖

1.建立一個藍圖的包,例如users,並在__init__.py檔案中建立藍圖物件

from flask import Blueprint
# 1. 建立藍圖目錄並對藍圖物件進行初始化
users_blue = Blueprint("users",__name__,template_folder="users_templates",static_folder='users_static',static_url_path="/libs")

2.在這個藍圖目錄下, 建立views.py檔案,儲存當前藍圖使用的檢視函式

from . import users_blue
from flask import render_template
# 2. 編寫檢視
@users_blue.route("/")
def index():
    return render_template("index.html",title="users/index/index.html")

@users_blue.route("/list")
def list():
    return "users/list"

3.users/__init__.py中引入views.py中所有的檢視函式

# 3. 註冊檢視
from .views import *

4.在主應用main.py檔案中的app物件上註冊這個users藍圖物件

# 4. 註冊藍圖
from users import users_blue
app.register_blueprint(users_blue,url_prefix="/users")

當這個應用啟動後,通過/users/可以訪問到藍圖中定義的檢視函式

3.藍圖的url字首

當我們在應用物件上註冊一個藍圖時,可以指定一個url_prefix關鍵字引數(這個引數預設是/)

  • 在應用最終的路由表 url_map中,在藍圖上註冊的路由URL自動被加上了這個字首,這個可以保證在多個藍圖中使用相同的URL規則而不會最終引起衝突,只要在註冊藍圖時將不同的藍圖掛接到不同的自路徑即可

  • url_for在使用時,如果要生成一個藍圖裡面的檢視對應的路由地址,則需要宣告當前藍圖名稱+檢視名稱

url_for('users.home') # /users/home

4.註冊藍圖的靜態檔案的相關路由

1.static_folder:設定靜態檔案目錄

和應用物件不同,藍圖物件建立時不會預設註冊靜態目錄的路由。需要我們在 建立時指定 static_folder 引數。

下面的示例將藍圖所在目錄下的static_users目錄設定為靜態目錄

from flask import Blueprint
# 通過static_folder引數設定靜態檔案目錄
users_blue = Blueprint("users",__name__,static_folder='users_static')

 

2.static_url_path:改變靜態檔案的路由

定製靜態目錄URL規則 :可以在建立藍圖物件時使用 static_url_path 來改變靜態目錄的路由。

下面的示例將為 users/static 資料夾的路由設定為 /lib

 

from flask import Blueprint
# 通過static_url_path設定靜態檔案路由
users_blue = Blueprint("users",__name__,static_folder='users_static',static_url_path='/lib')

訪問http://127.0.0.1:5000/users/libs/1.jpg 即可檢視到圖片

5.設定藍圖中模板的目錄

藍圖物件預設的模板目錄為系統的模版目錄,可以在建立藍圖物件時使用 template_folder 關鍵字引數設定模板目錄

users_blue = Blueprint("users",__name__,static_folder='users_static',static_url_path='/libs',template_folder='users_templates')

注意:如果在 templates 中存在和 templates_users 有同名模板檔案時, 則系統會優先使用 templates 中的檔案

4.藍圖的執行機制

1.藍圖執行機制的簡要介紹

  • 藍圖是儲存了一組將來可以在應用物件上執行的操作,註冊路由就是一種操作

  • 當在app物件上呼叫 route 裝飾器註冊路由時,這個操作將修改物件的url_map路由表

  • 然而,藍圖物件根本沒有路由表,當我們在藍圖物件上呼叫route裝飾器註冊路由時,它只是在內部的一個延遲操作記錄列表defered_functions中新增了一個項

  • 當執行app物件的 register_blueprint() 方法時,應用物件將從藍圖物件的 defered_functions 列表中取出每一項,並以自身作為引數執行該匿名函式,即呼叫應用物件的 add_url_rule() 方法,這將真正的修改應用物件的usr_map路由表

2.藍圖執行機制的詳細介紹

 

相關文章