主頁 > 後端開發 > Flask-資料庫操作

Flask-資料庫操作

2020-10-15 20:44:26 後端開發

目錄
  • 一、什么是ORM
  • 二、Flask-SQLAlchemy安裝及設定
    • 1. 安裝
    • 2. 資料庫連接設定
  • 三、資料庫基本操作
    • 1. 增刪改
    • 2. 查詢
    • 3. 查詢練習
  • 四、綜合案例-圖書管理
    • 1. 圖書館測驗資料顯示
    • 2. 圖書館添加資料
    • 3. 圖書館洗掉書籍
    • 4. 圖書館洗掉作者
    • 5. 圖書館CSRFProtect應用
    • 6. 表單的創建
    • 7. library.html
  • 五、多對多
    • 1. 需求分析
    • 2. 代碼
  • 六、資料庫遷移

一、什么是ORM

  • ORM 全拼Object-Relation Mapping. 稱為物件-關系映射
  • 主要實作模型物件到關系資料庫資料的映射.
    • 比如:把資料庫表中每條記錄映射為一個模型物件

關系映射

二、Flask-SQLAlchemy安裝及設定

1. 安裝

  • 安裝 flask-sqlalchemy
pip install flask-sqlalchemy
  • 如果連接的是 mysql 資料庫,需要安裝 mysqldb
pip install flask-mysqldb

提示: 如果flask-mysqldb安裝不上,推薦安裝, pip install pymysql

2. 資料庫連接設定

  • 設定資料庫的鏈接地址,追蹤資訊
  • 格式:mysql://<用戶名>:<密碼>@:<埠>/資料庫名稱
# 資料庫鏈接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
# 動態追蹤修改設定,如未設定只會提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

查看映射的sql陳述句,設定: app.config['SQLALCHEMY_ECHO'] = True

  • 配置完成需要去 MySQL 中創建專案所使用的資料庫
$ mysql -uroot -pmysql
$ create database test charset utf8;
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

#2.設定資料庫的配置資訊
#設定資料庫的鏈接資訊,
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:[email protected]:3306/test"
#該欄位增加了大量的開銷,會被禁用,建議設定為False
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False


#3.創建sqlalchemy物件db,關聯app
db = SQLAlchemy(app)

# 4.撰寫模型類,欄位,繼承自db.Model
class Student(db.Model):
    __tablename__ = "students"
    #主鍵, 引數1: 表示id的型別, 引數2: 表示id的約束型別
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32))

@app.route('/')
def hello_world():

    return "helloworld"

if __name__ == '__main__':

    #洗掉繼承自db.Model的表
    db.drop_all()

    #5.創建資料庫的表,創建的是繼承自db.Model的表
    db.create_all()

    app.run(debug=True)

三、資料庫基本操作

  • 在Flask-SQLAlchemy中,插入、修改、洗掉操作,均由資料庫會話管理,
    • 會話用 db.session 表示,在準備把資料寫入資料庫前,要先將資料添加到會話中然后呼叫 db.session.commit() 方法提交會話,
  • 在 Flask-SQLAlchemy 中,查詢操作是通過 query 物件操作資料,
    • 最基本的查詢是回傳表中所有資料,可以通過過濾器進行更精確的資料庫查詢,

1. 增刪改

"""
增刪改

- 全部都是使用db.session操作
- 常見方法:
  - db.session.add(obj) 添加單個物件
  - db.session.add_all([obj1,obj2]) 添加多個物件
  - db.session.delete(obj) 洗掉單個物件
  - db.session.commit() 提交會話
  - db.drop_all() 洗掉繼承自db.Model所有表
  - db.create_all() :創建繼承自db.Model的所有表
  - 其他:
    - db.session.rollback() 回滾
    - db.session.remove() 移除會話
  - 案例: 撰寫兩個模型類, 一個角色模型類,  還有一個用戶模型類
    - 關系: 一對多

"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

#1.設定資料庫的配置資訊
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:[email protected]:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

#2.創建SQLalchemy物件,關聯app
db = SQLAlchemy(app)

#3.撰寫模型類
#角色(一方)
class Role(db.Model):
    __tablename__ = "roles"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32))

    #如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<Role:%s>"%self.name

#用戶(多方)
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32))

    #建立外鍵
    role_id = db.Column(db.Integer,db.ForeignKey(Role.id))

    #如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<User:%s>"%self.name

@app.route('/')
def hello_world():

    return "helloworld"

if __name__ == '__main__':

    #為了演示方便,先洗掉表,后創建
    db.drop_all()
    db.create_all()

    app.run(debug=True)

使用ipython進行測驗,前提是先進行安裝

2. 查詢

# -*- coding = utf-8 -*-
# @Time : 2020/10/2 10:15
# @Author : md

'''

查詢練習
'''

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)


# 1.設定資料庫的配置資訊
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:[email protected]:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# app.config["SQLALCHEMY_ECHO"] = True


# 2.創建SQLalchemy物件,關聯app
db = SQLAlchemy(app)


# 3.撰寫模型類
# 角色(一方)
class Role(db.Model):
    __tablename__ = "roles"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 關系資料寫在這個表中,也就是寫在一方這個表中
    # 為了查詢方便,不會產生物體欄位
    # 給role添加了一個users屬性, 那么查詢的方式是, role.users
    # 給user添加了一個role屬性, 那么查詢的方式是, user.role

    # 重點 建立關系,這里的名字為想要建立關系的模型名字
    # 解釋:前半句話是給Role(本模型)模型添加一個users屬性,因為這兩個資料庫通外鍵連接
    # 所以,可以通過這個表的物件,就可以訪問User表中的資料,例如:查看角色是admin的所有用戶role.users
    # 后半句是給本(自己)模型添加一個role屬性,這樣User表中的物件,就可以訪問本表中的資料,可以知道某個用戶是什么身份
    # 例如查看用戶的身份,user.role
    # lazy="dynamic" 是懶加載
    # backref反向參考
    users = db.relationship("User", backref="role", lazy="dynamic")

    # 如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<Role:%s>" % self.name


# 用戶(多方)
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    email = db.Column(db.String(32))
    password = db.Column(db.String(32))

    # 建立外鍵
    role_id = db.Column(db.Integer, db.ForeignKey(Role.id))

    # 如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<User:%s,%s,%s,%s>" % (self.id, self.name, self.email, self.password)

@app.route('/')
def hello_world():

    return "helloworld"


if __name__ == '__main__':

    # 為了演示方便,先洗掉表,后創建
    db.drop_all()
    db.create_all()

    # 創建測驗資料
    ro1 = Role(name='admin')
    db.session.add(ro1)
    db.session.commit()

    # 再次插入一條資料
    ro2 = Role(name='user')
    db.session.add(ro2)
    db.session.commit()

    # 多條用戶資料
    us1 = User(name='wang', email='[email protected]', password='123456', role_id=ro1.id)
    us2 = User(name='zhang', email='[email protected]', password='201512', role_id=ro2.id)
    us3 = User(name='chen', email='[email protected]', password='987654', role_id=ro2.id)
    us4 = User(name='zhou', email='[email protected]', password='456789', role_id=ro1.id)
    us5 = User(name='tang', email='[email protected]', password='158104', role_id=ro2.id)
    us6 = User(name='wu', email='[email protected]', password='5623514', role_id=ro2.id)
    us7 = User(name='qian', email='[email protected]', password='1543567', role_id=ro1.id)
    us8 = User(name='liu', email='[email protected]', password='867322', role_id=ro1.id)
    us9 = User(name='li', email='[email protected]', password='4526342', role_id=ro2.id)
    us10 = User(name='sun', email='[email protected]', password='235523', role_id=ro2.id)
    db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10])
    db.session.commit()

    app.run(debug=True)
  • 其中realtionship描述了Role和User的關系,
  • 第一個引數為對應參照的類"User"
  • 第二個引數backref為類User,反向參考屬性

第三個引數lazy決定了什么時候SQLALchemy從資料庫中加載資料

  • 如果設定為子查詢方式(subquery),則會在加載完Role物件后,就立即加載與其關聯的物件,這樣會讓總查詢數量減少,但如果回傳的條目數量很多,就會比較慢
    • 設定為 subquery 的話,role.users 回傳所有資料串列
  • 另外,也可以設定為動態方式(dynamic),這樣關聯物件會在被使用的時候再進行加載,并且在回傳前進行過濾,如果回傳的物件數很多,或者未來會變得很多,那最好采用這種方式

User.query.filter().all()

3. 查詢練習

查詢所有用戶資料
User.query.filter().all()
此時過濾器可以不寫
User.query.all()


查詢有多少個用戶
User.query.count()



查詢第1個用戶
User.query.first()


查詢id為4的用戶[3種方式]
User.query.get(4) 此時get里面是主鍵

 User.query.filter(User.id == 4).all() 回傳的是串列,但滿足的只有一個

User.query.filter(User.id == 4).first()

User.query.filter_by(id=4).first()




查詢名字結尾字符為g的所有資料[開始/結尾/包含]
User.query.filter(User.name.startswith('g')).all()

 User.query.filter(User.name.endswith('g')).all()

User.query.filter(User.name.contains('g')).all()


查詢名字不等于wang的所有資料
User.query.filter(User.name != 'wang').all()


查詢名字和郵箱都以 li 開頭的所有資料
User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()


查詢password是 123456 或者 email 以 itheima.com 結尾的所有資料
from sqlalchemy import or_
User.query.filter(or_(User.password == '123456',User.email.endswith('itheima.com'))).all()



查詢id為 [1, 3, 5, 7, 9] 的用戶串列
User.query.filter(User.id.in_([1,3,5,7,9])).all()


查詢name為liu, 的角色資料
user = User.name.filter(User.name == 'liu').first()
role = Role.query.filter(Role.id == user.role_id).first()


查詢所有用戶資料,并以郵箱排序
 User.query.order_by(User.email).all()
 User.query.order_by(User.email.desc()).all()





每頁3個,查詢第2頁的資料

#page: 表示要查詢的頁數
#per_page: 表示每頁有多少條資料
#Error_out: 建議寫成False,查不到不會報錯
paginate = User.query.paginate(page,per_page,Error_out)

paginate.pages #總頁數
paginate.page #當前頁
paginate.items #當前的物件串列


查詢前兩條資料
 User.query.limit(2).all()


lazy="dynamic"

四、綜合案例-圖書管理

目的:

  • 表單創建
  • 資料庫操作
  • 一對多關系演練

實作步驟:

  • 1.創建資料庫配置資訊,定義模型類
  • 2.創建資料庫表,添加測驗資料
  • 3.撰寫html頁面,展示資料
  • 4.添加資料
  • 5.洗掉書籍,洗掉作者

1. 圖書館測驗資料顯示

  • 步驟
    • 1.查詢所有作者資訊
    • 2.攜帶作者資訊,渲染頁面

2. 圖書館添加資料

  • 添加的邏輯分析:
    • 1.如果作者存在,書籍存在, 不能添加
    • 2.如果作者存在,書籍不存在,可以添加
    • 3.如果作者不存在,可以添加

3. 圖書館洗掉書籍

  • 步驟
    • 1.根據書籍編號獲取書籍物件
    • 2.洗掉書籍物件
    • 3.重定向到頁面展示

4. 圖書館洗掉作者

  • 步驟
    • 1.根據作者編號獲取作者物件
    • 2.遍歷洗掉,作者書籍物件
    • 3.洗掉作者,提交資料庫
    • 4.重定向到頁面展示

5. 圖書館CSRFProtect應用

  • 作用: 防止csrf攻擊的
  • 使用步驟:
    • 1.匯入類CSRFProtect
    • 2.使用CSRFProtect保護app
      • 一旦使用POST,PUT,DELTE,PATCH方式提交的時候就需要校驗csrf_token
    • 3.需要設定SECRET_KEY,用來加密csrf_token
    • 4.設定csrf_token到表單中

6. 表單的創建

# -*- coding = utf-8 -*-
# @Time : 2020/10/2 16:07
# @Author : md


from flask import Flask, render_template, request, redirect, flash
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)

# 由于使用了flash,所以得設定
app.config["SECRET_KEY"] = "wepricsjf"

# 使用 CSRFProtect保護app
CSRFProtect(app)


# 1.設定資料庫的配置資訊
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:[email protected]:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 生成對應的sql陳述句在控制臺
# app.config["SQLALCHEMY_ECHO"] = True


# 2.創建SQLalchemy物件,關聯app
db = SQLAlchemy(app)


# 3.撰寫模型類
# 作者(一方)
class Author(db.Model):
    __tablename__ = "authors"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 關系資料,必須有外鍵為基礎
    books = db.relationship("Book", backref="author")

    # 如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<Author:%s>" % self.name


# 書籍(多方)
class Book(db.Model):
    __tablename__ = "books"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 建立外鍵
    author_id = db.Column(db.Integer, db.ForeignKey(Author.id))

    # 如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<Book:%s,%s>" % (self.id, self.name)


# 5. 展示資料
@app.route('/')
def hello_world():
    # 1. 查詢所有的作者資訊,因為作者有外鍵,可以通過關系資料方便的查出該作者對應的書籍
    authors = Author.query.all()

    return render_template("library.html", authors=authors)


# 6. 添加資料
@app.route("/add_data", methods=["POST"])
def add_data():
    # 1. 獲取提交的資料
    author_name = request.form.get("author")
    book_name = request.form.get("book")

    # 先判斷輸入的內容是否為空
    if not all([author_name, book_name]):
        flash("作者或書籍不能為空")
        return redirect("/")


    # 2. 根據作者資訊查詢作者物件
    author = Author.query.filter(Author.name == author_name).first()
    # 3. 判斷作者是否存在
    if author:
        # 4. 通過書籍名稱查詢書籍物件,并且這本書的作者的id和查詢出來的作者的id一樣
        # 也就是查看要添加的這本書是不是該作者寫的
        book = Book.query.filter(Book.name == book_name, Book.author_id == Author.id).first()
        # 5. 判斷書籍是否存在
        if book:
            # return "該作者已經寫了這本書了"
            flash("已經有該作者寫的這本書了")
        else:
            # 創建書籍物件,添加到資料庫
            book = Book(name=book_name, author_id=author.id)
            db.session.add(book)
            db.session.commit()
    else:
        # 作者不存在也是可以添加的
        # 先在作者表中進行添加
        author = Author(name=author_name)
        db.session.add(author)
        db.session.commit()

        # 然后再書籍表中進行添加
        book = Book(name=book_name, author_id=author.id)
        db.session.add(book)
        db.session.commit()

    # 6. 重定向到首頁
    return redirect("/")


# 7. 洗掉書籍
@app.route("/delete_book/<int:book_id>")
def delete_book(book_id):
    # 1. 根據id獲取到書籍物件
    book = Book.query.get(book_id)
    # 2. 洗掉這個書籍
    db.session.delete(book)
    db.session.commit()
    # 3. 重定向到頁面
    return redirect("/")


# 7. 洗掉作者
@app.route("/delete_author/<int:author_id>")
def delete_author(author_id):
    # 1. 根據id獲取到作者物件
    author = Author.query.get(author_id)
    # 2. 這個作者的全部書籍,由于使用了關系資料,直接這樣寫就可以
    books = author.books
    # 3. 遍歷這個作者的全部書籍
    for book in books:
        db.session.delete(book)
    # 4. 洗掉作者
    db.session.delete(author)
    db.session.commit()

    # 5. 重定向到頁面
    return redirect("/")


if __name__ == '__main__':
    # 為了演示方便,先洗掉后創建
    db.drop_all()
    db.create_all()

    # 4. 添加測驗資料庫
    # 生成資料
    au1 = Author(name='老王')
    au2 = Author(name='老尹')
    au3 = Author(name='老劉')
    # 把資料提交給用戶會話
    db.session.add_all([au1, au2, au3])
    # 提交會話
    db.session.commit()

    bk1 = Book(name='老投訓憶錄', author_id=au1.id)
    bk2 = Book(name='我讀書少,你別騙我', author_id=au1.id)
    bk3 = Book(name='如何才能讓自己更騷', author_id=au2.id)
    bk4 = Book(name='怎樣征服美麗少女', author_id=au3.id)
    bk5 = Book(name='如何征服英俊少男', author_id=au3.id)
    # 把資料提交給用戶會話
    db.session.add_all([bk1, bk2, bk3, bk4, bk5])
    # 提交會話
    db.session.commit()

    app.run()

7. library.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{# action: 提交到的地址, method: 表示提交的方式 #}
<form action="/add_data" method="post">
{# 設定隱藏欄位csrf_token , 只要使用了CSRFProtect,然后使用模板渲染的時候就可以直接使用csrf_token()方法#}
    <input type="hidden" name="csrf_token" value="https://www.cnblogs.com/mengd/p/{{ csrf_token() }}">

    作者: <input type="text" name="author"><br>
    書籍: <input type="text" name="book"><br>
    <input type="submit" value="https://www.cnblogs.com/mengd/p/添加"><br>
    {% for message in get_flashed_messages() %}
        <span style="color: red;">{{ message }}</span>
    {% endfor %}
</form>

<hr>

{# 資料展示 #}
<ul>
    {# 遍歷作者 #}
    {% for author in authors %}
{#        <li>作者: {{ author.name }}</li>#}
{#        <li>作者: {{ author.name }} <a href="https://www.cnblogs.com/delete_author/{{ author.id }}">洗掉</a></li>#}
        <li>作者: {{ author.name }} <a href="https://www.cnblogs.com/mengd/p/{{ url_for("delete_author",author_id=author.id) }}">洗掉</a></li>

        {# 遍歷作者的書籍 #}
        <ul>
            {% for book in author.books %}
{#                <li>書籍: {{ book.name }} </li>#}
                <li>書籍: {{ book.name }} <a href="https://www.cnblogs.com/delete_book/{{ book.id }}">洗掉</a></li>
            {% endfor %}

        </ul>
    {% endfor %}

</ul>



</body>
</html>

五、多對多

在專案開發程序中,會遇到很多資料之間多對多關系的情況,比如:

  • 學生網上選課(學生和課程)
  • 老師與其授課的班級(老師和班級)
  • 用戶與其收藏的新聞(用戶和新聞)
  • 等等...

所以在開發程序中需要使用 ORM 模型將表與表的多對多關聯關系使用代碼描述出來,多對多關系描述有一個唯一的點就是:需要添加一張單獨的表去記錄兩張表之間的對應關系

1. 需求分析

  • 學生可以網上選課,學生有多個,課程也有多個
  • 學生有:張三、李四、王五
  • 課程有:物理、化學、生物
  • 選修關系有:
    • 張三選修了化學和生物
    • 李四選修了化學
    • 王五選修了物理、化學和生物

需求:

  1. 查詢某個學生選修了哪些課程
  2. 查詢某個課程都有哪些學生選擇

2. 代碼

# -*- coding = utf-8 -*-
# @Time : 2020/10/2 19:30
# @Author : md


'''
多對多,學生和課程
'''

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)


# 1.設定資料庫的配置資訊
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:[email protected]:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# app.config["SQLALCHEMY_ECHO"] = True


# 2.創建SQLalchemy物件,關聯app
db = SQLAlchemy(app)


# 3.撰寫模型類
# 學生
class Student(db.Model):
    __tablename__ = "students"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 關系資料,使用在多對多中的時候注意secondary這個屬性,是中間表的表名,用來二次查詢
    courses = db.relationship("Course", backref="students", secondary="td_student_course")

    # 如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<Role:%s>" % self.name


# 課程
class Course(db.Model):
    __tablename__ = "courses"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 如果一個類繼承自object那么重寫__str__方法即可, 如果是繼承自db.Model那么需要重寫__repr__方法
    def __repr__(self):
        return "<User:%s>" % self.name


# 中間表
db.Table(
    "td_student_course",
    db.Column("student_id", db.Integer, db.ForeignKey(Student.id)),
    db.Column("course_id", db.Integer, db.ForeignKey(Course.id))
)

@app.route('/')
def hello_world():

    return "helloworld"



# 為了演示,先洗掉后創建
db.drop_all()
db.create_all()

stu1 = Student(name='張三')
stu2 = Student(name='李四')
stu3 = Student(name='王五')

cou1 = Course(name='物理')
cou2 = Course(name='化學')
cou3 = Course(name='生物')

stu1.courses = [cou2, cou3]
stu2.courses = [cou2]
stu3.courses = [cou1, cou2, cou3]

db.session.add_all([stu1, stu2, stu2])
db.session.add_all([cou1, cou2, cou3])

db.session.commit()


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

六、資料庫遷移

  • 目的: 當資料庫的表結構發生變化之后,如果直接洗掉原有的資料,再添加新的資料,有可能導致資料丟失
  • 注意點:
    • 1.是為了備份表結構,而不是資料
    • 2.如果想要備份資料,需要使用工具,navicat,mysqlworkbench,等等
    • 3.更新的程序資料一般不會丟失,做降級的時候需要謹慎操作
  • 操作流程:
    • 1.安裝擴展
      • pip install flask_script
      • pip install flask_migrate
    • 2.匯入三個類
      • from flask_script import Manager
      • from flask_migrate import Migrate, MigrateCommand
    • 3.通過Manager類創建物件manager,管理app
      • manager = Manager(app)
    • 4.使用Migrate,關聯db,app
      • Migrate(app,db)
    • 5.給manager添加一條操作命令
      • manager.add_command("db",MigrateCommand)
    • 相關遷移命令:
      • 生成遷移檔案夾[一次就好]
        • python xxx.py db init
      • 將模型類生成遷移腳本[重復執行]
        • python xxx.py db migrate -m '注釋'
      • 將遷移腳本更新到資料庫中[重復執行]
        • python xxx.py db upgrade/downgrade [version]
      • 其他命令
        • 查看最新版本的命令
          • python xxx.py db show
        • 查看當前版本
          • python xxx.py db current
        • 查看所有的歷史版本
          • python xxx.py db history
# -*- coding = utf-8 -*-
# @Time : 2020/10/2 20:38
# @Author : md

from flask import Flask
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 設定資料庫配置資訊
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:123456@localhost:3306/test1"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

# 創建SQLAlchemy物件,關聯app
db = SQLAlchemy(app)


# 3. 通過Manager類創建物件manager,管理app
manager = Manager(app)

# 4.使用Migrate,關聯db,app
Migrate(app, db)

# 5.給manager添加一條操作命令
manager.add_command("db", MigrateCommand)


# 6.撰寫模型類
class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
   # email = db.Column(db.String(32))


@app.route('/')
def hello_world():
    return "helloworld"


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

生成遷移檔案夾

將模型類生成遷移腳本

將遷移腳本更新到資料庫中

此時就可以在資料庫中看到對應的表了

此時在代碼中多寫一行,添加一列

然后繼續執行這兩條命令,就會看到資料表結構中就多了一列

還可以進行降級

然后再升級到指定的版本

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/173132.html

標籤:Python

上一篇:Form組件、auth認證組件、自定義圖片驗證碼登錄、 自定義分頁

下一篇:Excel的資料可視化和Python的有什么不同?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more