通过ORM模型类操作数据:重点
操作数据库(增删改查)
查:
模型类.query : 得到了该模型的所有结果集
模型类.query.过滤器: 得到的又是一个新的结果集
模型类.query.过滤器.执行器: 取出集里面的数据
注意点:
1.如果不指定数据的表名称,那么默认就是类名称的小写
2.如果需要指定,通过__tablename__ = '自定义表名'
增删改:
db.create_all(): 创建继承自db.Model的模型类
db.drop_all(): 删除数据库中所有的表(继承db.Model)
db.session.add(obj) 添加单个对象
db.session.add_all([obj1,obj2]) 增加多个
db.session.delete(obj) 删除当个对象
db.session.commit() 提交会话
db.session.rollback() 回滚
db.session.remove() 移除会话
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
#2. 设置数据库配置信息
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:123456@127.0.0.1:3306/basic4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 3.创建对象
db = SQLAlchemy(app)
#角色模型(一方)
class Role(db.Model):
__tablename__ = 'roles'
#主键, 参数1:表示类型, 参数2: 约束范围
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique=True)
# 4.用户模型(多方)
class Person(db.Model):
#主键, 参数1:表示类型, 参数2: 约束范围
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique=True)
#外键
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(): 创建继承自db.Model的模型类的表
db.create_all()
#添加对象到数据
haha = Role(name=’admin’)
db.session.add(haha)
db.session.commit()
p1 = Person(name='banzhang', role_id=haha.id)
db.session.add(p1)
db.session.add_all([p1,p2])
db.session.commit()
app.run(debug=True)
注意点:
1.如果不指定数据的表名称,那么默认就是类名称的小写
2.如果需要指定,通过__tablename__ = '自定义表名'
数据库增加,删除,修改操作:
增加:
user = User(name='laowang')
db.session.add(user)
db.session.commit()
修改:
user.name = 'xiaohua'
db.session.commit()
删除:
db.session.delete(user)
db.session.commit()
查询所有用户数据
User.query.all()
查询有多少个用户
User.query.count()
查询第1个用户
User.query.all()[0]
查询id为4的用户[3种方式]
User.query.get(4)
User.query.filter_by(id = 4).first()
User.query.filter(User.id == 4).first()
查询名字结尾字符为g的所有数据[开始/包含]
User.query.filter(User.name.endswith('g')).all()
User.query.filter(User.name.startswith('g')).all()
User.query.filter(User.name.contains('g')).all()
查询名字不等于wang的所有数据[2种方式]
User.query.filter(User.name!=’wang’).all()
from sqlalchemy import not_
User.query.filter(not_(User.name=’wang’))
查询名字和邮箱都以 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` 以 `itheima.com` 结尾的所有数据
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.query.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页的数据
paginate = User.query.paginate(page, per_page,Error_out)
paginate = User.query.paginate(2,3,False)
page: 哪一个页
per_page: 每页多少条数据
Error_out: False 查不到不报错
pages: 共有多少页
items: 当前页数的所有对象
page: 当前页
Relationship,backref,lazy(项目常用)
问题1: 如果查询到角色数据之后,能不能快速查询到,哪些用户扮演了该角色
role = Role.query.get(1)
一般做法:
users_list = User.query.filter(User.role_id == role.id).all()
需要做到: 使用关系relationship,添加在一方
users_list = role.users
需要在Role 中添加属性:
users = db.relationship(“User”)
括号内填的是对应的类的名字,通过外键之间的关联直接使用查询到的当前的角色信息查找对应职位的员工,role.users。
问题2: 如果查询到用户数据之后,能不能快速查询到,该用户扮演了哪个角色
user = User.query.get(1)
一般做法:
role = Role.query.get(user.role_id)
需要做到: 需要使用到反向关系属性backref
role = user.role
users = db.relationship(“User”,backref=’role’)
lazy: 懒加载,默认值是subquery,一旦查询到一个对象之后,会默认把其他关联的数据也查询出来,相当于默认执行上面的user.role,role.users,使用这些语句会返回对象,需要用all()方法返回。
可以设置成dynamic,只有用到才去查
users = db.relationship(“User”,backref=’role’,lazy=”dynamic”)
多对多
#中间表,学生课程中间表
tb_student_course = db.Table(
#表名
"tb_student_course",
#参数1:表示字段值, 参数2: 数据类型, 参数3: 外键 连接的表名的字段值
db.Column("student_id",db.Integer,db.ForeignKey("students.id")),
db.Column("course_id",db.Integer,db.ForeignKey("courses.id")))
#学生
class Student(db.Model):
__tablename__ = "students"
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique=True,nullable=False)
#关系属性 secondary设置多对多的连接表,多对多关系关系属性在哪个表设置都可以
courses = db.relationship("Course",backref="students",secondary=tb_student_course)
#为了查看方便
def __repr__(self):
return "<Student:%s>"%self.name
class Course(db.Model):
__tablename__ = "courses"
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique=True,nullable=False)
def __repr__(self):
return "<Course:%s>"%self.name
数据库迁移
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
2.使用Manager管理app
manager = Manager(app)
- 使用Migrate,关联app,db
Migrate = (app,db)
- 给manager,添加一个数据库操作命令
manager.add_command("db"(名称),MigrateCommand)
5.通过命令方式迁移 在中端执行
生成迁移脚本文件夹(一次就好)
python xxx.py db(是数据库操作命令的名称) init
将模型类,迁移成脚本(重复执行) 会在文件夹中生成一个版本
python xxx.py db migrate -m '注释'
将迁移脚本跟新到数据库(重复执行)
python xxx.py db upgrade / downgrade [version]
查看当前版本
python demo02flask_migrate.py db current
查看最新版本
python demo02flask_migrate.py db show
注意点:
1.迁移是备份的表结构,不是数据
2.降级有可能导致数据丢失
3.如果需要做数据备份,需要使用功能,比如: navicat, mysqlworkbench,等等工具