Flask-SQLalchemy flask的ORM模型
使用ORM模型的原因
當項目越來越大的時候 會出現很多問題
- 原生SQL較多 重複使用率低
- 如果你的數據庫發生了改變 所有的原生SQL就都要進行修改
- 寫原生SQL的時候 會有安全隱患
ORM:中文件關係對象的映射 使用ORM去操作數據庫的時候 不會再去寫原生的SQL了 通過把表映射成 類 字段爲你的屬性 ORM在執行的時候 也會最終轉換爲 SQL語句 去操作數據庫
- 易用性 使用ORM可以減少重複SQL的概率 寫出來的模型也更加的直觀清晰
- 可移植性 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 '刪除'
四、數據庫操作
查詢集
查詢數據的集合
分類
- 原始查詢集
類名.query得到的結果就爲原始查詢集
- 數據查詢集
加上各種的過濾器的方法 最終返回的結果 爲數據查詢集 都使用數據查詢集
過濾器
(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) 比較運算符
__gt__
__ge__
__lt__
__le__
>
<
>=
<=
==
!=
@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
注意
如果當前存在 模型 但是執行創建遷移文件的時候 提示沒有任何改變的時候 需要查看當前的模型類是否有使用(導入)