flask框架資料庫部分(四)

Wise-發表於2020-11-11

1.資料庫基本介紹

資料庫特點

  • 持久化儲存
  • 讀寫速度極高
  • 保證資料的有效性
  • 對程式支援性很好

資料庫理解

  • 資料行(記錄)
  • 資料列(欄位)
  • 資料表(資料行的集合)
  • 資料庫(資料表的集合)

MySQL

是一個關係型資料庫管理系統。
特點

  • 使用C、C++編寫,使用了多種編譯器測試,保證原始碼的可移植性
  • 支援多種作業系統,Linux、Windows、AIX、FreeBSD、HP-UX、MacOS、NovellNetware、OpenBSD、OS/2Wrap、Solaris
  • 為多種程式語言提供了API,如C、C++、Python、Java、Perl、PHP、Eiffel、Ruby
  • 支援多執行緒,充分利用CPU資源
  • 優化的SQL查詢演算法,有效地提高查詢速度
  • 提供多種語言支援,常見的編碼如GB2312、BIG5、UTF8
  • 提供TCP/IP、ODBC和JDBC等多種資料庫連線途徑
  • 提供用於管理、檢查、優化資料庫操作的管理工具
  • 大型的資料庫。可以處理擁有上萬條的大型資料庫
  • 支援多種儲存引擎
  • 採用了雙授權政策,分為社群版和商業版,體積小,速度快,總體擁有成本低,開放原始碼的特點。中小網站開發都選擇使用MySQL作為網站資料庫。
  • MySQL使用標準的SQL資料語言形式
  • MySQL是可以制定的,才用了GPL協議,可以修改原始碼來開發自己的MySQL系統
  • 線上DDL更改功能
  • 複製全域性事務標識
  • 複製無崩潰從機
  • 複製多執行緒從機

2.SQLALchemy介紹和基本使用

使用準備
資料庫是一個網站的基礎。flask可以使用很多資料庫,如MySQL、MongoDB、SQLite、PostgreSQL等。以MySQL為例,如果想要運算元據庫,我們可以使用ORM來運算元據庫。
flask中的資料庫操作之前,先要安裝的模組:

  • mysql:Windows在官網下載。Ubuntu,通過sodu apt-get install mysql-server libmysqlclient-dev -yq
  • pymysql:是用Python來操作mysql的包。
  • SQLALchemy:是一個資料庫ORM框架。
    通過SQLALchemy連線資料庫
from sqlalchemy import create_engine  #匯入庫 建立搜尋引擎
#資料庫的配置變數
HOSTNAME='127.0.0.1'   #連線資料庫的域名
PORT='3306'  #資料庫監聽的埠號
DATABASE='XXXX'  #  資料庫的名字
USERNAME='root'  #連線資料庫的使用者名稱
PASSWORD='root'  #連線資料庫的密碼

#固定格式
DB_URI='myql+pymysql://{}:{}@{}:{}/{}'.fromat(USERNAME,PORT,DATABASE,USERNAME,PASSWORD)
#建立搜尋引擎
engine=create_engine(DB_URL)
#建立連線
with engine.connect() as con:
	result = con.execute('select * from students')
	print(result.fetchone())
	
#資料庫配置選項單獨放在一個constans.py的檔案中

首先從sqlalchemy中匯入create_engine,這個函式建立引擎,然後用engine.connect()來連線資料庫。通過create_engine函式中的DB_URI,需要傳遞一個滿足某種格式的字串。
dialect+driver://username:password@host:port/database?charset=utf8

使用SQLALchemy執行原生SQL

from sqlalchemy import create_engine
from constants import DB_URI

#連線資料庫
engine = create_engine(DB_URI,echo=True)
# 使用with語句連線資料庫,如果發生異常會被捕獲
with engine.connect() as con:
    # 先刪除users表
    con.execute('drop table if exists authors')
    # 建立一個users表,有自增長的id和name
    con.execute('create table authors(id int primary key auto_increment,'name varchar(25))')
    # 插入兩條資料到表中
    con.execute('insert into persons(name) values("abc")')
    con.execute('insert into persons(name) values("xiaotuo")')
    # 執行查詢操作
    results = con.execute('select * from persons')
    # 從查詢的結果中遍歷
    for result in results:
        print(result)

3.ORM介紹

隨著專案增大,採用原生SQL的方式在程式碼中會出現大量的SQL語句,對專案的進展非常不利

  • SQL語句重複利用率不高,越複雜的SQL語句條件越多,程式碼越長。
  • 很多SQL語句是在業務邏輯中拼出來的,如果資料庫需要更改,就要去修改這些邏輯,很容易漏掉某些SQL語句的修改
  • 寫SQL時容易忽略web安全問題

ORM:Object Relationship Mapping,物件關係對映,通過ORM我們可以通過類的方式去運算元據庫,而不是寫原生的SQL語句。通過把表對映成類,把行作為例項,把欄位作為屬性,ORM在執行物件操作時候最終還是會把對應的操作轉換為資料庫原生語句。

使用ORM的優點

  • 易用性:使用ORM做資料庫開發可以有效減少SQL語句,寫出來的模型也更見直觀
  • 效能損耗小
  • 設計靈活:可以輕鬆寫出來複雜的查詢
  • 可移植性:SQLALchemy封裝了底層的資料庫實現,支援多個關係型資料庫,包括MySQL,SQLite

使用SQLALchemy
要使用ORM來運算元據庫,首先需要建立一個類來與對應的表進行對映。現在User表來作為例子,它有自增長的id、name、fullname、password這些欄位

from sqlalchemy import create_engine,Column,Integer,String
from constants import DB_URL  #在constants檔案中 匯入DB_URL
from sqlalchemy.ext.declarative import declarative_base

engine=create_engine(DB_URL,echo=True)

#所有類都要繼承'declarative_base'這個函式生成的基類
Base=declarative_base(engine)
class User(Base):
	#定義表名為users
	__tablename__='user'
	#將id設定為主鍵,並且預設是增長的
	id=Column(Integer,primary_key=True)
	#name欄位,字元型別,最大的長度是50個字元
	name=Column(String(50))
	fullname=Column(String(50))
	password=Column(String(100))
	#讓列印出來的資料更好看,可選的
	def __repr__(self):
		return '<User(id='%s', name='%s', fullname='%s', password='%s')>'%(self.id, self.name, self.fullname, self.password)

sqlalchemy會自動的設定第一個Integer的主鍵並且沒有被標記為外來鍵的欄位新增自增長的屬性。因此以上例子中id自動變成自增長的。以上建立完表和表對映的類後,還沒有真正的對映到資料庫中,執行以下程式碼將類對映到資料庫中。

Base.metadata.create_all()

在建立完資料表,並且做完和資料庫的對映後,接下來讓我們新增資料進去

ed_user=User(name='haha',fullname='liang haha', password='edspassword')
#列印名字,密碼, id 來檢查
print(en_user.name,ed_user.password, ed_user.id)

name和password可以正常列印,id為None,這是因為id是一個自增長的主鍵,還未插入到資料庫中,id不存在。

我們把建立的資料插入到資料庫中。
用Session物件。

from sqlalchemy.orm import sessionmaker
Session=sessionmaker(bind=engine)
#或者使用下面這種
#Session=sessionmaker()
#Session.conffigure(bind=engine)

session=Session()
ed_user=User(name='haha',fullname='lianghaah',password='edspassword')
session.add(ed_user)

只把資料新增到session中,但是並沒有真正的把資料儲存到資料庫中。如果需要把資料儲存到資料庫中,還要做一次commit操作。

session.commit()
#列印ed_userd的id
print(ed_user.id)

ed_user就已經有id。說明已經插入到資料庫中。在sqlalchemy的ORM實現中,在做commit操作之前,所有的操作都是在事務中進行的,因此如果你要將事務中的操作真正的對映到資料庫中,還需要做commit操作。既然用到了事務,這裡就並不能避免的提到一個回滾操作了,一下程式碼展示瞭如何使用回滾。

#修改ed_user的使用者名稱
ed_user.name='Edwaro'
#建立一個新使用者
fake_user=User(name='fakeuser', fullname='Invalid', password='123456')
#將建立的fake_user新增到session中
session.add(fake_user)

#判斷'fake_user'是否在 'session'中存在
print(fake_user in session)

#從資料庫中查詢name=Ed使用者
tmp_user=session.query(User).filter_by(name='Edwardo')
#列印tmp_user的name
print(temp)
#列印出查詢到的tmp_user物件,注意這個物件的name屬性已經在事務中被修改為Edwardo
><User(name='Edwardo', fullname='Ed', password='edspassword')>
#剛剛所有的操作都是在事務中進行的,現在來做回滾操作
session.rollback()
#在列印出tmp_user
print(tmp_user)


#再看fake_user是否還在session中
print(fake_user in session)

進行查詢操作,查詢操作是通過session.query()方法實現的,這個方法會返回一個Query物件,Query物件相當於一個陣列,裝載了查詢出來的資料,並且可以進行迭代。具體裡面裝的什麼資料,就要看向session.query()方法傳的什麼引數了,如果只是傳一個ORM的類名作為引數,那麼提取出來的資料就是都是這個類的例項了

for instance in session.query(User).order_by(User.id):
	print(instance)

如果傳遞了兩個及其以上的物件,或者是傳遞的是ORM類的屬性,那麼查詢出來的就是元組

for instance in session.query(User.name):
	print(inistance)
for instance in session.query(User.name,User.fullname):
    print(instance)
for instance in session.query(User,User.name).all():
    print(instance)

如果想對結果進行過濾,可以使用filter_by和filter兩個方法,這兩個方法都是用來做過濾的,區別在於,filter_by是傳入關鍵字引數,filter是傳入條件判斷,並且filter能夠傳入的條件更多更靈活。

# 第一種:使用filter_by過濾:
for name in session.query(User.name).filter_by(fullname='Ed Jones'):
    print(name)

# 第二種:使用filter過濾:
for name in session.query(User.name).filter(User.fullname=='Ed Jones'):
    print(name)

4.SQLALchemy屬性常用資料型別

sqlalchemy常用資料型別

  • Integer:整型
  • Float:浮點整型
  • Boolean:傳遞True/False進去
  • DECIMAL:定點型別
  • enum:列舉型別
  • Date:傳遞datetime.date()進去
  • DateTime:傳遞datetime.datetime()進去
  • Time:傳遞datetime.time()進去
  • String:字元型別,使用時需要指定長度,區別於Text型別
  • Text:文字型別
  • LONGTEXT:長文字型別

Column常用引數

  • default:預設值
  • nullable:是否為空
  • primary_key:是否為主鍵
  • unique:是否唯一
  • autoincrement:是否自動增長
  • onupdate:更新的時候執行的函式
  • name:該屬性在資料庫中的欄位對映

query可用引數
1.模型物件。指定查詢這個模型中所有的物件
2.模型中的屬性。可以指定只查詢某個模型的其中幾個屬性
3.聚合函式。

  • func.count:統計行的數量
  • func.avg:求平均值
  • func.max:求最大值
  • func.min:求最小值
  • func.sum:求和

過濾物件
過濾是資料提取的一個很重要的功能,過濾條件都是隻能通過filter方法實現的。
equals

query.filter(User.name=='ed')

not equals

query.filter(User.name != 'ed')

like

query.filter(User.name.like('%ed%'))

in

query.filter(User.name.in_(['ed','wendy','jack']))
# 同時,in也可以作用於一個Query
query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))))

not in

query.filter(~User.name.in_(['ed','wendy','jack']))

is null

query.filter(User.name==None)
#或者是
query.filter(User.name.is_(None))

is not null

query.filter(User.name != None)
# 或者是
query.filter(User.name.isnot(None))

and

from sqlalchemy import and_
query.filter(and_(User.name=='ed',User.fullname=='Ed Jones'))
# 或者是傳遞多個引數
query.filter(User.name=='ed',User.fullname=='Ed Jones')
# 或者是通過多次filter操作
query.filter(User.name=='ed').filter(User.fullname=='Ed Jones')

or

from sqlalchemy import or_
query.filter(or_(User.name=='ed', User.name=='wendy'))

1.外來鍵及其四種約束

外來鍵
子啊MySQL中,外來鍵可以讓表之間的關係更加緊密。而sqlalchemy也支援外來鍵。通過ForeignKey類來實現,並且可以指定表的外來鍵約束

class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer,primary_key=True,autoincrement=True)
    title = Column(String(50),nullable=False)
    content = Column(Text,nullable=False)
    uid = Column(Integer,ForeignKey('user.id'))
    def __repr__(self):
        return "<Article(title:%s)>" % self.title
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer,primary_key=True,autoincrement=True)
    username = Column(String(50),nullable=False)

外來鍵約束有以下幾項:
1.PESTRICT:父表資料被刪除,會阻止刪除。預設就是這一項。
2.NO ACTION:在MySQL中,同RESTRICT
3.CASCADE:級聯刪除
4.SET NULL:父表資料被刪除,子表資料會設定為NULL

表關係
表之間的關係存在三種:一對一、一對多、多對多。而sqlalchemy中的ORM也可可以模擬這三種關係。因為一對一其實在SQLAlchemy中底層是通過一對多的方式模擬的。

一對多
拿之前的user表為例,假如現在要新增一個功能,要儲存使用者的郵箱帳號,並且郵箱帳號可以有多個,這時候就必須建立一個新的表,用來儲存使用者的郵箱,然後通過user.id來作為外來鍵進行引用

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer,primary_key=True)
    email_address = Column(String,nullable=False)
    user_id = Column(Integer,ForeignKey('users.id'))
    user = relationship('User',backref="addresses")
    def __repr__(self):
        return "<Address(email_address='%s')>" % self.email_address

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer,primary_key=True)
    name = Column(String(50))
    fullname = Column(String(50))
    password = Column(String(100))
    addresses = relationship("Address",backref="user")

一對一
是一對多的特殊情況,一對應的是User表,而多對應的是Address,也就是說一個User物件有多個Address。因此要將一對多轉換成一對一,要設定一個User物件對應一個Address物件即可

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer,primary_key=True)
    name = Column(String(50))
    fullname = Column(String(50))
    password = Column(String(100))

    addresses = relationship("Address",backref='addresses',uselist=False)
    
class Address(Base):
    __tablename__ = 'addresses'
    id = Column(Integer,primary_key=True)
    email_address = Column(String(50))
    user_id = Column(Integer,ForeignKey('users.id')
    user = relationship('Address',backref='user')

只要在User表中的addresses欄位上新增uselist=False就可以達到一對一效果。

多對多
多對多需要一箇中間表來作為連線,在sqlalchemy中的orm也需要一箇中間表。

association_table = Table(
    'teacher_classes',
    Base.metadata,
  	Column('teacher_id',Integer,ForeignKey('teacher.id')),
  	Column('classes_id',Integer,ForeignKey('classes.id'))
  )

class Teacher(Base):
    __tablename__ = 'teacher'
    id = Column(Integer,primary_key=True)
    tno = Column(String(10))
    name = Column(String(50))
    age = Column(Integer)
    classes = relationship('Classes',secondary=association_table,backref='teachers')

 class Classes(Base):
    __tablename__ = 'classes'
    id = Column(Integer,primary_key=True)
    cno = Column(String(10))
    name = Column(String(50))
    teachers = relationship('Teacher',secondary=association_table,backref='classes')

要建立一個多對多的關係表,首先需要一箇中間表,通過table來建立一箇中間表。

6.排序和查詢高階

排序
1.order_by:可以指定根據這個表中的某個欄位進行排序,如果在前面加了一個,代表的是降序排序。
2.在模型定義的時候指定預設排序:有些時候,不想每次在查詢的時候都指定排序的方式,可以在定義模型的時候就指定排序的方式。

  • 在模型中定義,新增以下程式碼
__mapper_args__={
		"order_by":title
}
  • 即可讓文章使用標題來進行排序
    3.正向排序和反向排序:預設情況是從小到大排序,從前到後排序的,如果想要反向排序,可以呼叫排序的欄位的desc方法

limit、offset和切片

  • limit:可以限制每次查詢的時候只查詢幾條資料
  • offset:可以限制查詢資料的時候過濾前面多少條
  • 切片:可以對Query物件使用切片操作,來獲取想要的資料

查詢高階
group_by
根據某個欄位進行分組。比如想要根據性別進行分組,來統計每個分組分別有多少人

session.query(User.gender,func.count(User.id)).group_by(User.gender).all()

having
having是對查詢結果進一步過濾。比如只想要看未成年人的數量,那麼可以首先對年齡進行分組統計人數,然後再對分組進行having過濾。

result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all()

join方法
join查詢分為兩種,一種是inner join,另一種是outer join。預設的是inner join,如果指定left join或者是right join則為outer join。如果想要查詢User及其對應的Address

for u,a in session.query(User,Address).filter(User.id==Address.user_id).all():
    print(u)
    print(a)

通過join的方式來實現

for u,a in session.query(User,Address).join(Address).all():
    print(u)
    print(a)

採用outerjoin,可以獲取所有user,而不用在乎這個user是否有address物件,並且outerjoin預設為左外查詢:

for instance in session.query(User,Address).outerjoin(Address).all():
	print(instance)

別名
當多表查詢的時候,有時候同一個表要用到多次,這個時候別名就可以方便的解決命名衝突的問題

from sqlalchemy.orm import aliased
adalias1 = aliased(Address)
adalias2 = aliased(Address)
for username,email1,email2 in session.query(User.name,adalias1.email_address,adalias2.email_address).join(adalias1).join(adalias2).all():
    print(username,email1,email2)

子查詢
sqlalchemy也支援子查詢,比如現在要查詢一個使用者的使用者名稱以及該使用者的郵箱地址數量。要滿足這個需求,可以在子查詢中找到所有使用者的郵箱數〈(通過group by合併同一使用者),然後再將結果放在父查詢中進行使用:

from sqlalchemy.sql import func
# 構造子查詢
stmt = session.query(Address.user_id.label('user_id'),func.count(*).label('address_count')).group_by(Address.user_id).subquery()
# 將子查詢放到父查詢中
for u,count in session.query(User,stmt.c.address_count).outerjoin(stmt,User.id==stmt.c.user_id).order_by(User.id):
    print u,count

一個查詢如果想要變為子查詢,則是通過subquery()方法實現,變成子查詢後,通過子查詢.c屬性來訪問查詢出來的列。如果查詢整個實體,則需要通過aliased方法

stmt = session.query(Address)
adalias = aliased(Address,stmt)
for user,address in session.query(User,stmt).join(stmt,User.addresses):
print user,address

7.Flask-SQLALchemy外掛

另外一個框架,叫做Flask-SQLAlchemy,Flask-SQLAlchemy是對SQLAlchemy進行了一個簡單的封裝,使得我們在flask中使用sqlalchemy更加的簡單。可以通過pipinstall flask-sqlalchemy

  • 資料庫初始化
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from constants import DB_URI
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
db = SQLAlchemy(app)
  • ORM類
class User(db.Model):
  id = db.Column(db.Integer,primary_key=True)
  username = db.Column(db.String(80),unique=True)
  email = db.Column(db.String(120),unique=True)
  
  def __repr__(self):
      return '<User %s>' % self.username
  • 對映模型到資料庫表:使用Flask-SQLAlchemy所有的類都是繼承自db.Model,並且所有的column和資料型別也都成為db的一個屬性。但是有個好處是不用寫表名了,Flask-SQLAlchemy會自動將類名小寫化,然後對映成表名。
    寫完類模型後,要將模型對映到資料庫的表中,使用以下程式碼建立所有的表:
db.create_all()
  • 新增資料:可以在資料庫中看到生成的user表
admin = User('admin','admin@example.com')
guest = User('guest','guest@example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
  • 新增資料之前的沒有區別,只是session成為了一個db的屬性

  • 查詢資料:查詢資料不再是之前的session.query了,而是將query屬性放在了db. Model上,所以查詢就是通過Model.query的方式進行查詢了

users = User.query.all()
  • 刪除資料:刪除資料跟新增資料類似,只不過session是db的一個屬性
db.session.delete(admin)
db.session.commit()

8.Flask-Script

介紹
Flask-Script的作用是可以通過命令列的形式來操作Flask。例如通過命令跑一個開發版本的伺服器、設定資料庫,定時任務等。使用Flask-Script,通過pip install flask-script安裝

from flask_script import Manager
from your_app import app
manager = Manager(app)
@manager.command
def hello():
    print('hello')
if __name__ == '__main__':
    manager.run()

我們把指令碼命令程式碼放在一個叫做manage.py檔案中,然後在終端執行python manage.pyhello命令,就可以看到輸出hello了

定義命令的三種方法
1.使用@command裝飾器
2.使用類繼承Command類

from flask_script import Command,Manager
from your_app import app
manager = Manager(app)
class Hello(Command):
    "prints hello world"
    def run(self):
        print("hello world")

manager.add_command('hello',Hello())

使用類的方式

  • 必須繼承自Command基類
  • 必須實現run方法
  • 必須通過add_command方法新增命令

3.使用option裝飾器:想要在使用命令的時候還傳遞引數進去,使用@option裝飾器更加方便。

@manager.option('-n','--name',dest='name')
def hello(name):
    print('hello ',name)

呼叫hello命令

python manage.py -n juran
python manage.py --name juran

新增引數到命令中

  • option裝飾器
@manager.option('-n', '--name', dest='name', default='joe')
@manager.option('-u', '--url', dest='url', default=None) 
def hello(name, url): 
  if url is None: 
     print("hello", name)
  else: 
      print("hello", name, "from", url)
  • command裝飾器:可以新增引數,不靈活
@manager.command 
def hello(name="Fred") 
  print("hello", name)
  • 類繼承:可以新增引數
from flask_Flask import Comman,Manager,Option

class Hello(Command):
  option_list = (
      Option('--name','-n',dest='name'),
  )

  def run(self,name):
      print("hello %s" % name)

要在指定引數的時候,動態的做一些事情,可以使用get_options方法

class Hello(Command):
  def __init__(self,default_name='Joe'):
self.default_name = default_name

  def get_options(self):
      return [
          Option('-n','--name',dest='name',default=self.default_name),
      ]
  def run(self,name):
      print('hello',name)

9.Flask-Migrate

簡要介紹
在實際的開發環境中,經常會發生資料庫修改的行為。一般我們修改資料庫不會直接手動的去修改,而是去修改ORM對應的模型,然後再把模型對映到資料庫中。這時候如果有一個工具能專門做這種事情,就顯得非常有用了,而flask-migrate就是做這個事情的。flask-migrate是基於Alembic進行的一個封裝,並整合到Flask中,而所有的遷移操作其實都是Alembic做的,他能跟蹤模型的變化,並將變化對映到資料庫中。安裝pip install flask-migrate

flask-migrate
要讓Flask-Migrate能夠管理app中的資料庫,需要使用Migrate(app,db)來繫結app和資料庫

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from constants import DB_URI
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
# 繫結app和資料庫
migrate = Migrate(app,db)
class User(db.Model):
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(20))
    addresses = db.relationship('Address',backref='user')
class Address(db.Model):
    id = db.Column(db.Integer,primary_key=True)
    email_address = db.Column(db.String(50))
    user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
db.create_all()
@app.route('/')
def hello_world():
    return 'Hello World!'
if __name__ == '__main__':
    app.run()

初始化一個遷移資料夾

flask db init

然後再把當前的模型新增到遷移檔案中

flask db migrate

最後再把遷移檔案中對應的資料庫操作,真正的對映到資料庫

flask db upgrade

manage.py檔案
這個檔案用來存放對映資料庫的命令,MigrateCommand是flask-migrate整合的一個命令,因此想要新增到指令碼命令中,需要採用manager.add_command(‘db’,MigrateCommand)的方式,以後執行python manage.py dbxxx的命令,其實就是執行MigrateCommand

from flask_script import Manager
from flask_migrate import MigrateCommand, Migrate
from exts import db
from demo import app
from models import User

manage = Manager(app)
Migrate(app, db)
manage.add_command("db", MigrateCommand)

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

相關文章