day96:flask:flask-migrate&flask-session&藍圖Blueprint&藍圖的執行機制
目錄
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:[email protected]: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.藍圖執行機制的詳細介紹
&n