1. Flask-SQLAlchemy
安装
pip install flask-sqlalchemy
# 如果连接的是 mysql 数据库,需要安装 mysqldb
pip install flask-mysqldb
数据库连接设置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test'
# 动态追踪修改设置,如未设置只会提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
常用的SQLAlchemy字段类型
常用的SQLAlchemy列选项
常用的SQLAlchemy关系选项
2. 数据库基本操作
- 在Flask-SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理。
- 会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 commit() 方法提交会话。
- 在 Flask-SQLAlchemy 中,查询操作是通过 query 对象操作数据。
- 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。
定义模型
class Role(db.Model):
# 定义表名
__tablename__ = 'roles'
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
us = db.relationship('User', backref='role')
#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(64), unique=True, index=True)
email = db.Column(db.String(64),unique=True)
password = db.Column(db.String(64))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return 'User:%s'%self.name
模型中关联关系
class Role(db.Model):
...
#关键代码
users = db.relationship('User', backref='role', lazy='dynamic')
class User(db.Model):
...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
- 其中realtionship描述了Role和User的关系。在此文中,第一个参数为对应参照的类"User"
- 第二个参数backref为类User申明新属性的方法
- 第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据
- 如果设置为子查询方式(subquery),则会在加载完Role对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢
- 设置为 subquery 的话,role.users 返回所有数据列表
- 另外,也可以设置为动态方式(dynamic),这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式
- 设置为 dynamic 的话,role.users 返回查询对象,并没有做真正的查询,可以利用查询对象做其他逻辑,比如:先排序再返回结果
- 如果设置为子查询方式(subquery),则会在加载完Role对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢
SQLAlchemy查询过滤器
SQLAlchemy查询执行器
创建表
db.create_all()
删除表
db.drop_all()
查询
- filter_by精确查询
# 返回名字等于wang的所有人
User.query.filter_by(name='wang').all()
- first()返回查询到的第一个对象
User.query.first()
- all()返回查询到的所有对象
User.query.all()
- filter模糊查询
# 返回名字结尾字符为g的所有数据
User.query.filter(User.name.endswith('g')).all()
- get():参数为主键,如果主键不存在没有返回内容
User.query.get()
- 逻辑非
# 返回名字不等于wang的所有数据
User.query.filter(User.name!='wang').all()
- not_ 相当于取反
from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()
- 逻辑与,需要导入and,返回and()条件满足的所有数据
from sqlalchemy import and_
User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()
- 逻辑或,需要导入or_
from sqlalchemy import or_
User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()
- 查询数据后删除
user = User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()
- 更新数据
user = User.query.first()
user.name = 'dong'
db.session.commit()
User.query.first()
- 查询角色的所有用户
#查询roles表id为1的角色
ro1 = Role.query.get(1)
#查询该角色的所有用户
ro1.us.all()
- 查询用户所属角色
#查询users表id为3的用户
us1 = User.query.get(3)
#查询用户属于什么角色
us1.role
示例演练
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://information:information@127.0.0.1:3306/information'
# 动态追踪修改设置,如未设置只会提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# 角色 1的一方
class Role(db.Model):
# 指定该模型对应数据库中的表名,如果不指定为类名小写
__tablename__ = "roles"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
# backref 在这行代码的作用是,给前面的 User 添加一个属性,名字叫backref的值
# 以便可以直接通过 user.role 方法到一的一方的数据
users = db.relationship('User', backref='role')
def __repr__(self):
return 'Role %d %s' % (self.id, self.name)
# 用户 多的一方
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, index=True)
email = db.Column(db.String(64),unique=True)
password = db.Column(db.String(64))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return 'User:%s'%self.name
@app.route('/')
def index():
return 'index'
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='wang@163.com', password='123456', role_id=ro1.id)
us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id)
us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id)
us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id)
us5 = User(name='tang', email='tang@qq.com', password='158104', role_id=ro2.id)
us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id)
us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id)
us8 = User(name='liu', email='liu@qq.com', password='867322', role_id=ro1.id)
us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id)
us10 = User(name='sun', email='sun@163.com', 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)
"""
查询所有用户数据
User.query.all()
查询有多少个用户
User.query.count()
查询第1个用户
User.query.first()
查询id为4的用户[3种方式]
User.query.get(4)
User.query.filter_by(id=4).first()
User.query.filter(User.id == 4).first()
查询名字结尾字符为g的所有数据[startswith/包含contains]
User.query.filter(User.name.endswith('g')).all()
查询名字不等于wang的所有数据[2种方式]
User.query.filter(not_(User.name == 'wang')).all()
User.query.filter(User.name != 'wang').all()
查询名字和邮箱都以 li 开头的所有数据[2种方式]
User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all()
User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all()
查询password是 `123456` 或者 `email` 以 `163.com` 结尾的所有数据
User.query.filter(or_(User.passwd == '123456', User.email.endswith('163.com))).all()
查询id为 [1, 3, 5, 7, 9] 的用户列表
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all
查询name为liu的角色数据
User.query.filter(User.name == 'liu').first().role
查询所有用户数据,并以邮箱排序
User.query.order_by(User.email).all()
每页3个,查询第2页的数据
paginate = User.query.paginate(2, 3) 第一个参数代表查询第几页,第二个参数代表每页几个
paginate.items 当前页数据
paginate.pages 总页数
paginate.page 当前页
"""
3. 数据库迁移
环境
pip install flask-migrate
示例代码
from flask import Flask
from flask_migrate import Migrate, MigrateCommand
# MigrateCommand 迁移命令
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.secret_key = 'aaasas'
# 设置连接数据
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://information:information@127.0.0.1:3306/information'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 实例化SQLAlchemy对象
db = SQLAlchemy(app)
# 使用迁移类将应用和数据库连接对象保存起来
Migrate(app, db)
# 创建终端命令的对象
manager = Manager(app)
# 将数据库的迁移命令添加到manager中
manager.add_command('aaa', MigrateCommand)
# 定义模型Role
class Role(db.Model):
# 定义表名
__tablename__ = 'roles'
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
user = db.relationship('User', backref='role')
# repr()方法显示一个可读字符串,
def __repr__(self):
return 'Role:'.format(self.name)
# 定义用户
class User(db.Model):
__talbe__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
#设置外键
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return 'User:'.format(self.username)
if __name__ == '__main__':
manager.run()
创建迁移脚本
- 自动创建迁移脚本有两个函数
- upgrade():函数把迁移中的改动应用到数据库中。
- downgrade():函数则将改动删除。
- 自动创建的迁移脚本会根据模型定义和数据库当前状态的差异,生成upgrade()和downgrade()函数的内容。
- 对比不一定完全正确,有可能会遗漏一些细节,需要进行检查
迁移操作:
1.python 文件 db init
2.python 文件 db migrate -m"版本名(注释)"
3.python 文件 db upgrade 然后观察表结构
4.根据需求修改模型
5.python 文件 db migrate -m"新版本名(注释)"
6.python 文件 db upgrade 然后观察表结构
7.若返回版本,则利用 python 文件 db history查看版本号
8.python 文件 db downgrade(upgrade) 版本号
---------------------------------------------------END-----------------------------------------------
---------------------------------------------------END-----------------------------------------------