1. 程式人生 > >Flask:05-一首歌的時間掌握flask資料模型(01)

Flask:05-一首歌的時間掌握flask資料模型(01)

資料模型

資料庫回顧

  • 分類:
    • 關係型資料庫:MySQL、sqlite、…
    • 非關係型資料庫:Redis、MongoDB、…
  • 操作:
    • 執行原生SQL語句,每次都需要拼接SQL語句,非常繁瑣而且特別容易出錯。
    • ORM(物件關係對映),使用ORM可以通過對物件的操作完成對資料庫的操作。

flask-sqlalchemy

  • 說明:其實是sqlalchemy擴充套件庫在flask中的移植庫,通過了絕大多數關係型資料庫的支援(ORM)

  • 安裝:pip install flask-sqlalchemy

  • 連線地址配置:

    • 名稱:SQLALCHEMY_DATABASE_URI
    • 格式:
      • sqlite:sqlite:/// + 資料庫檔名
      • MySQL:資料庫名+驅動名://使用者名稱:密碼@主機:埠/資料庫
  • 使用:

    # 配置資料連線地址
    base_dir = os.path.dirname(__file__)
    database_uri = 'sqlite:///' + os.path.join(base_dir, 'data.sqlite')
    app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
    # 禁止資料的修改追蹤(需要消耗資源)
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    
    # 建立資料庫操作物件
    db = SQLAlchemy(app)
    
    # 設計模型類
    class User(db.Model): # 表名預設會將模型名轉為小寫加下劃線的形式 # 如:UserModel => user_model # 指定表名 __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), unique=True) email = db.Column(db.String(32), unique=True)
  • 資料表操作

    @app.route('/create/')
    def create(): # 建立資料表 db.create_all() return '資料表已建立' @app.route('/drop/') def drop(): db.drop_all() return '資料表已刪除' # 新增終端命令,完成資料表的建立 @manager.command def createall(): # 先刪除原來的,副作用很大 db.drop_all() # 然後再建立 db.create_all() return '資料表已建立' # 新增終端命令,完成資料表的刪除 @manager.command def dropall(): if prompt_bool('您確定要刪庫跑路嗎?'): db.drop_all() return '資料表已刪除' return '刪庫有風險,操作需謹慎!'

    執行終端命令:python manage.py createall,即可建立資料表

資料庫遷移

  • 說明:將資料模型的更改應用到資料表的操作叫資料庫遷移。flask-migrate就是專門做遷移的擴充套件庫。

  • 安裝:pip install flask-migrate

  • 使用:

    from flask_migrate import Migrate
    
    # 建立資料庫遷移物件
    migrate = Migrate(app, db)
    
    # 將遷移命令新增到終端
    manager.add_command('db', MigrateCommand)
    
  • 遷移:

    • 初始化,只需要一次,建立使用者存放遷移指令碼的目錄及相關檔案。
    python manage.py db init
    
    • 根據資料模型與資料表,生成遷移指令碼。
    python manage.py db migrate
    
    • 執行遷移指令碼
    python manage.py db upgrade
    
  • 提示:

    • 初始化操作只需要一次,以後生成遷移指令碼與執行遷移指令碼迴圈執行即可完成資料庫的遷移。
    • 不是每次遷移都會成功,遷移出錯時需要手動解決。

CURD操作

  • 增加資料

    # 設定自動提交操作,請求結束時無論如何都會提交
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
    
    # 增加資料
    @app.route('/insert/')
    def insert():
        # 建立物件
        # jie = User(name='八戒', email='[email protected]', age=30)
        # hou = User(name='猴哥', email='[email protected]', age=20)
        # 儲存到資料庫,只能儲存一條資料
        # db.session.add(hou)
    
        bei = User(name='貝貝', email='[email protected]', age=28)
        jing = User(name='晶晶', email='[email protected]', age=18)
        huan = User(name='歡歡', email='[email protected]', age=22)
        ying = User(name='迎迎', email='[email protected]', age=23)
        ni = User(name='妮妮',email='[email protected]',
        age=20)
    
        # 儲存到資料庫,一次性儲存多條資料
        db.session.add_all([bei, jing, huan, ying, ni])
    
        # 提交操作,若沒有設定自動提交,每次執行操作都需要手動提交一次
        # db.session.commit()
    
        return '資料已新增'
    
  • 查詢資料

    # 查詢操作
    @app.route('/select/<uid>/')
    def select(uid):
        # 根據主鍵進行查詢,找到返回物件,沒找到返回None
        user = User.query.get(uid)
        if user:
            return user.name
        return '查無此人'
    
  • 修改資料

    # 修改資料
    @app.route('/update/<uid>/')
    def update(uid):
        user = User.query.get(uid)
        if user:
            user.email = '[email protected]'
            # 再次新增到資料庫即可
            db.session.add(user)
            return '資料已修改'
        return '查無此人'
    
  • 刪除資料

    # 刪除資料
    @app.route('/delete/<uid>/')
    def delete(uid):
        user = User.query.get(uid)
        if user:
            db.session.delete(user)
            return '資料已刪除'
        return '查無此人'
    

模型設計參考

  • 常見的欄位型別

    欄位型別python型別說明
    Integer int 整型(32)
    SmallInteger int 整型(16)
    BigInteger int/long 整型(64)
    Float float 浮點型
    String str 變長字串
    Text str 不受限制的文字
    Boolean bool 布林值,True/False
    Date datetime.date 日期
    Time datetime.time 時間
    DateTime datetime.datetime 日期時間
    Interval datetime.timedelta 時間間隔
    PickleType pickle.dumps() 使用pickle模組序列化後的python物件
    LargeBinary bytes 任意大的二進位制資料
  • 常見欄位選項

    選項說明
    primary_key 是否作為主鍵索引,預設為False
    autoincrement 是否設定欄位自增,預設為False
    unique 是否作為唯一索引,預設為False
    index 是否作為普通索引,預設為False
    nullable 欄位是否可以為空,預設為True
    default 設定預設值
  • 總結:

    • 插入資料可以不傳值的情況:自增的欄位、可以為空的欄位、有預設值的欄位
    • 使用flask-sqlalchemy時每個模型都需要有一個主鍵,通常主鍵欄位名稱為id
    • 資料模型類名與資料表中的名字
      • 預設:會將模型名轉換為小寫加下劃線的方式,如:UserModel => user_model
      • 指定:通過類屬性__tablename__指定表名

各種查詢

  • 說明:在資料庫的操作中,絕大多數都是查詢操作,而且這些操作都是通過方法來實現的。

  • 常見操作:

    操作說明
    get 根據主鍵查詢,查到返回物件,沒查到返回None
    get_or_404 根據主鍵查詢,查到返回物件,沒查到報404錯
    first 返回第一條資料,沒有時返回None
    first_or_404 返回第一條資料,沒有時報404錯
    all 查詢所有資料組成的列表
    limit 限制結果集數量,返回時查詢物件
    offset 結果集偏移數量,返回時查詢物件
    order_by 排序,指定欄位後,預設按升序排序(asc),降序(desc),可以指定多個欄位
    count 統計個數
  • 聚合函式:max、min、sum、avg、count

    from sqlalchemy import func
    
    @app.route('/query/')
    def query():
        # 聚合函式
        # max_age = db.session.query(func.max(User.age)).scalar()
        max_age = db.session.query(func.min(User.age)).scalar()
        return str(max_age)
    
  • 指定條件查詢

    @app.route('/query/')
    def query():
        # 指定等值條件
        # users = User.query.filter_by(age=18).all()
        # 指定任意條件
        users = User.query.filter(User.age > 18).all()
        return ','.join(u.name for u in users)
    

filter條件查詢

  • 關係

    >, __gt__:大於
    示例:     # users = User.query.filter(User.age > 20).all()
            # 等價於上式
            users = User.query.filter(User.age.__gt__(20)).all()
    >=,__ge__:大於等於
    <, __lt__:小於
    <=,__le__:小於等於
    ==,__eq__:等於
    !=,__ne__:不等於
    
  • 範圍

    users = User.query.filter(User.id.between(1, 3)).all()
    users = User.query.filter(User.id.in_((1, 3, 5))).all()
    users = User.query.filter(User.id.notin_((1, 3, 5))).all()
    
  • 內容

    # 包含指定內容
    # users = User.query.filter(User.email.contains('ng')).all()
    # 以指定內容開頭
    # users = User.query.filter(User.email.startswith('fe')).all()
    # 以指定內容結尾
    # users = User.query.filter(User.email.endswith('.com')).all()
    # 模糊匹配
    # users = User.query.filter(User.email.like('l%')).all()
    users = User.query.filter(User.email.notlike('l%')).all()
    
  • 邏輯

    from sqlalchemy import and_, or_
    
    # 預設的關係就是邏輯與
    # users = User.query.filter(User.id > 3, User.age > 20).all()
    # 與上式等價
    # users = User.query.filter(and_(User.id > 3, User.age > 20)).all()
    # 邏輯或
    users = User.query.filter(or_(User.id > 3, User.age > 20)).all()