flask入門5-model

Flask-SQLalchemy flask的ORM模型

使用ORM模型的原因

當項目越來越大的時候 會出現很多問題

  1. 原生SQL較多 重複使用率低
  2. 如果你的數據庫發生了改變 所有的原生SQL就都要進行修改
  3. 寫原生SQL的時候 會有安全隱患

ORM:中文件關係對象的映射 使用ORM去操作數據庫的時候 不會再去寫原生的SQL了 通過把表映射成 類 字段爲你的屬性 ORM在執行的時候 也會最終轉換爲 SQL語句 去操作數據庫

  1. 易用性 使用ORM可以減少重複SQL的概率 寫出來的模型也更加的直觀清晰
  2. 可移植性 ORM支持很多不同的數據庫

安裝:

sudo pip3 install flask-sqlalchemy

一、執行原生SQL

(1) 創建數據庫

create database if not exists 庫名 character set utf8;

(2) 安裝pymysql

sudo pip3 install pymysql

(3) 配置數據庫

DB_URI = 'mysql+pymysql://用戶名:密碼@主機:端口號/庫名'

實例

from sqlalchemy import create_engine

DATABASE = 'hz03'
USERNAME = 'root'
PASSWORD = '123456'
HOST = '127.0.0.1'
PORT = '3306'
#創建連接和操作數據庫的URI
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOST,PORT,DATABASE)

#創建操作數據庫的引擎
engine = create_engine(DB_URI)

with engine.connect() as con:
    # con.execute('create table user(id int,username varchar(255),sex tinyint)')
    con.execute('insert into user values(1,"xxx",1)')

二、在flask中使用ORM

(1) 當前字段類型

類型名 說明
integer 整形
SmallInteger 小整形
BigInteger 長整型
Float 浮點型
String varchar類型
Text 長文本
Boolean tingint
Date 日期 datetime.date
Time 時間 datetime.time
DateTime 時間和日期 datetime.datetim

(2) 約束條件

選項 選項說明
primary_key 主鍵 默認 False
index 常規 默認 False
Unique 唯一 默認 False
nullable 是否爲null 默認True
default 默認值

注意:

其中的default默認值 並不是更改表結構的默認值 而是在插入數據的時候 如果不插入數據 則插入默認值

實例

配置

from flask import Flask,render_template
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
#創建連接數據的URI
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]:3306/hz03'

app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True #開啓自動提交
#數據的追蹤 當數據發生改變時 會返回信號量 進行關閉 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
manager = Manager(app)

創建模型

class User(db.Model):
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(20),index=True)
    age = db.Column(db.Integer)
    icon = db.Column(db.String(40),default='default.jpg')

數據的添加修改刪除

@app.route('/create_table/')
def create_table():
    db.drop_all() #刪除 和當前模型類同名的表
    db.create_all() #創建當前模型類的表
    return '創建表'


@app.route('/insert/')
def insert():
    try:
        u = User(username='張三',age=18)
        # print(u)
        db.session.add(u)
        db.session.commit() #因爲sqlalchemy開啓事物 所有所以需要提交或者回滾
    except:
        db.session.rollback()
    return '添加數據'
#開啓了自動提交功能 不需要手動commit了
@app.route('/insert_two/')
def insert_two():
    u = User(username='李四',age=20)
    db.session.add(u)
    return '走我了'
#修改
@app.route('/update/')
def update():
    u = User.query.get(1)
    # print(u.id)
    # print(u.username)
    u.username = '王五'
    db.session.add(u)
    return 'update'

#刪除
@app.route('/delete/')
def delete():
    u = User.query.get(2) #查詢成功返回 對象 失敗返回None
    # print(u)
    db.session.delete(u)
    return '刪除'

拆分MVT

目錄結構

project/
    App/
        __init__.py  包文件必須的
        model.py    模塊
        views.py    視圖
    ext.py  extensions.py  加載第三方擴展的文件
    settings.py    配置文件
    static/
    templates/
    manage.py 啓動項

細緻的

project/
    App/
        __init__.py
        static/
            js/
            img/
            upload/
            css/
        templates/
            common/
            ...
        forms/
            __init__.py
            ...
        models/
            __init__.py
        views/
            __init.py__.py
            ...
        settings.py
        email.py
        extensions.py
    manager.py
    migrations/
    venv/

三、數據的操作

創建模型類

class User(Base,db.Model):
    __tablename__ = 'user' #給表起名
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(20),index=True)
    age = db.Column(db.Integer)
    icon = db.Column(db.String(40),default='default.jpg')
    def __init__(self,username='',age=0,icon='default.jpg'):
        self.username = username
        self.age = age
        self.icon = icon

(1) 添加 add add_all

添加一條

@main.route('/add/')
def add():
    u = User(username='張三',age=18)
    db.session.add(u)
    db.session.commit()
    return '數據添加一條成功'

添加多條

@main.route('/add_all/')
def add_all():
    u1 = User(username='李四',age=20)
    u2 = User(username='王五',age=22)
    db.session.add_all([u1,u2])
    db.session.commit()
    return '添加多條'

(2) 自定義增刪改的基礎類

class Base:
    #定義一個添加一條數據的方法
    def save(self):
        try:
            db.session.add(self)
            db.session.commit()
        except:
            db.session.rollback()

    #定義添加多條數據的方法
    @staticmethod
    def save_all(*args):
        try:
            db.session.add_all(args)
            db.session.commit()
        except:
            db.session.rollback()

    #自定義刪除方法
    def delete(self):
        try:
            db.session.delete(self)
            db.session.commit()
        except:
            db.session.rollback()

使用

class User(Base,db.Model):
    ...

在視圖中使用

@main.route('/add/')
def add():
    # u = User(username='張三',age=18)
    u = User('張三',18)
    # db.session.add(u)
    # db.session.commit()
    u.save() #使用自定義的添加方法
    return '數據添加一條成功'

@main.route('/add_all/')
def add_all():
    # u1 = User(username='李四',age=20)
    # u2 = User(username='王五',age=22)
    u1 = User('趙六',27)
    u2 = User('李七',12)
    # db.session.add_all([u1,u2])
    # db.session.commit()
    User.save_all(u1,u2)
    return '添加多條'

@main.route('/delete/')
def delete():
    u = User.query.get(1)
    u.delete()
    return '刪除'

四、數據庫操作

查詢集

查詢數據的集合

分類

  1. 原始查詢集

    類名.query得到的結果就爲原始查詢集

  2. 數據查詢集

    加上各種的過濾器的方法 最終返回的結果 爲數據查詢集 都使用數據查詢集

過濾器

(1) all 查詢所有 以列表形式返回 不支持連貫操作

類名.query.all()

@main.route('/all/')
def all():
    data = User.query.all()
    print(data)
    return render_template('show.html',data=data)

(2) filter() 過濾

類名.query.filter([類名.屬性名 條件操作符 值])

默認返回所有

#支持連貫操作
@main.route('/filter/')
def filter():
    # data = User.query.filter() #返回所有
    # data = User.query.filter(User.age>20) #查詢年齡大於20的數據
    data = User.query.filter(User.age>20,User.age<40) #查詢年齡大於20的數據 and 小於40
    print(data)
    return render_template('show.html',data=data)

(3) filter_by 只支持參數爲關鍵字參數

類名.query.filter_by(屬性名=值...)

@main.route('/filter_by/')
def filter_by():
    # data = User.query.filter_by(id=2)
    # data = User.query.filter_by(id>2) #錯誤寫法
    data = User.query.filter_by(id=2,age=27)
    return render_template('show.html',data=data)

(4) offset 偏移量

offset(num)

#偏移量取值
@main.route('/offset/')
def offset():
    data = User.query.filter().offset(2)
    return render_template('show.html',data=data)

(5) limit 取值

limit(num)

@main.route('/limit/')
def limit():
    # data = User.query.limit(2)
    data = User.query.filter(User.age>30).limit(2)
    return render_template('show.html',data=data)

(6) offset和limit組合使用

@main.route('/offsetlimit/')
def offsetlimit():
    data = User.query.offset(2).limit(2)
    # limit 2,2
    return render_template('show.html',data=data)

(7) order_by() 排序

@main.route('/order_by/')
def order_by():
    # data = User.query.order_by(User.age) #升序
    data = User.query.order_by(-User.age) #降序
    return render_template('show.html',data=data)

(8) first 取出第一條數據 返回對象

@main.route('/first/')
def first():
    # data = User.query.first() == User.query.get(2)
    print(data)
    print(data.id)
    print(data.username)
    return '取出第一條數據'

(9) get 獲取id對應的數據

查詢成功返回對象 查詢失敗 返回None

@main.route('/first/')
def first():
    data = User.query.get(2)
    return '取出第一條數據'

(10) contains 包含關係

@main.route('/contains/')
def contains():
    #username中包含數字7的數據
    data = User.query.filter(User.username.contains('7'))
    return render_template('show.html',data=data)

(11) like 模糊查詢

@main.route('/like/')
def like():
    #username中包含數字7的數據
    # data = User.query.filter(User.username.like('%7%'))
    # data = User.query.filter(User.username.like('李%')) #以李作爲開頭的
    data = User.query.filter(User.username.like('%6')) #以6作爲結尾的數據
    return render_template('show.html',data=data)

(12) startswith endswith 以...開頭 以...結尾

#startswith  endswith
@main.route('/startend/')
def startend():
    # data = User.query.filter(User.username.startswith('李'))
    data = User.query.filter(User.username.endswith('6'))
    return render_template('show.html',data=data)

(13) 比較運算符

  1. __gt__
  2. __ge__
  3. __lt__
  4. __le__
  5. >
  6. <
  7. >=
  8. <=
  9. ==
  10. !=
@main.route('/bjiao/')
def bjiao():
    # data = User.query.filter(User.age.__gt__(20))
    # data = User.query.filter(User.age.__ge__(99))
    data = User.query.filter(User.age!=99)
    return render_template('show.html',data=data)

(14) in 和 not in

@main.route('/in/')
def myIn():
    # data = User.query.filter(User.age.in_([27,12,1,30,40,50]))
    data = User.query.filter(~User.age.in_([27,12,1,30,40,50]))
    return render_template('show.html',data=data)

(15) is null

@main.route('/null/')
def null():
    # data = User.query.filter(User.username == None)
    # data = User.query.filter(User.username != None)
    # data = User.query.filter(User.username.is_(None))
    data = User.query.filter(User.username.isnot(None))
    return render_template('show.html',data=data)

(16) and_

多個條件 用逗號隔開,爲and操作

from sqlalchemy import and_

@main.route('/and/')
def myAnd():
    # data = User.query.filter(User.age==27,User.id==2)
    data = User.query.filter(and_(User.age==27,User.id==2))
    return render_template('show.html',data=data)

(17) or_

from sqlalchemy import or_

@main.route('/and/')
def myAnd():
    data = User.query.filter(or_(User.age==27,User.id==2))
    data = User.query.filter(and_(User.username.like('%6%')),or_(User.age>=27,User.id==2))
    return render_template('show.html',data=data)

(18) not_

from sqlalchemy import not_

@main.route('/and/')
def myAnd():    
    # data = User.query.filter(not_(User.age>27,User.id==1))\
    #錯誤寫法只能給一個條件取反
    data = User.query.filter(not_(User.age>27))
    return render_template('show.html',data=data)

(19) count 統計

    data = User.query.filter(not_(User.age>27)).count()

四、文件的遷移

模塊:

pip install flask-migrate

pip install flask-script

使用

(1) 實例化

from flask_migrate import Migrate,MigrateCommand
from flask_sqlalchemy import SQLalchemy
app = Flask(__name__)
db = SQLalchemy(app)
migrate = Migrate(app,db=db)
manager = Manager(app)
manager.add_command('db',MigrateCommand)

(2) 初始化 遷移文件目錄

python manage.py db init

(3) 生成遷移文件

python manage.py db migrate

(4) 執行遷移文件

python manage.py db upgrade

注意

如果當前存在 模型 但是執行創建遷移文件的時候 提示沒有任何改變的時候 需要查看當前的模型類是否有使用(導入)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章