1.安装扩展包, pip install flask_sqlalchemy
2.安装数据库驱动, pip install mysqldb / pymysql
3.导⼊SQLAlchemy类
4.配置数据库的链接信息等(可通过报错获取)
5.创建db = SQLAlchemy()对象,关联app
6.编写模型类,继承⾃db.Model
7.编写属性,db.Colomn(类型,约束信息)表示⼀列
8.操作(数据库的增删改查)
1.ORM不能创建数据库,只能创建表
2.默认情况下,⽣成的表名称是类名称的⼩写形式,如果需要指定,设置tablename
3.链接数据库的格式:
<协议名称>://<⽤户名>:<密码>@<ip地址>:<端⼝>/<数据库名>
如果使⽤的是mysqldb驱动,协议名: mysql
如果使⽤的是pymysql驱动,协议名: mysql+pymysql
1.设置表名: __tablename__ = 表名(字符串)
2.设置字段:字段名 = db.Column(db.数据类型,约束)
3设置外键:字段名 = db.Column(db.数据类型,db.ForeignKey(关联的表名.字段名))
注意:应设置__repr__方法,返回打印输出的格式,否则按默认方式返回
例:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 指定数据库的链接信息
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:zsh123@127.0.0.1:3306/basic12"
# 这个配置将来会被禁用,设置为True或者False可以解除警告信息,建议设置False
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
# 角色模型类(一方)
class Role(db.Model):
__tablename__ = "roles"
# db.Colomn()表示模型类的属性,
# 主键
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
def __repr__(self):
return "<Role:%s,%s>" % (self.id, self.name)
# 用户模型类(多方)
class User(db.Model):
__tablename__ = "users"
# db.Colomn()表示模型类的属性,
# 主键
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
email = db.Column(db.String(64), unique=True)
password = db.Column(db.String(64), unique=True)
# 外键,关联的是Role表中的主键id
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)
print(User.query.all())
方法 | 描述 |
---|---|
db.create_all() | 创建所有继承⾃db.Model的类 |
db.drop_all() | 删除所有继承⾃db.Model的类 |
db.session.add(obj) | 添加对象 |
db.session.add_all([obj1,obj2,…]) | 添加多个对象 |
db.session.delete(obj) | 删除对象 |
模型类.属性名 = xxx | 修改对象 |
db.session.commit() | 提交会话 |
db.session.rollback() | 回滚 |
db.session.remove() | 移除会话 |
注意:所有使数据库发生改变的操作都需要提交回话(db.session.commit())才会改变数据库
格式:User.query.查询过滤器.查询执行器
1.常用查询过滤器
过滤器 | 说明 |
---|---|
filter() | 把过滤器添加到原查询上,返回一个新查询 |
filter_by() | 把等值过滤器添加到原查询上,返回一个新查询 |
limit | 使用指定的值限定原查询返回的结果 |
offset() | 偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对原查询结果进行排序,返回一个新查询 |
group_by() | 根据指定条件对原查询结果进行分组,返回一个新查询 |
2.常用执行过滤器
方法 | 说明 |
---|---|
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如果未查到,返回None |
first_or_404() | 返回查询的第一个结果,如果未查到,返回404 |
get() | 返回指定主键对应的行,如不存在,返回None |
get_or_404() | 返回指定主键对应的行,如不存在,返回404 |
count() | 返回查询结果的数量 |
paginate() | 返回一个Paginate对象,它包含指定范围内的结果 |
例:
查询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.starstswith('g')).all()
User.query.filter(User.name.contains('g')).all()
查询名字不等于wang的所有数据[2种方式]
查询名字和邮箱都以 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: 当前页
1.一对多(有外键连接的前提):
一对多的数据库关系映射中,多方定义外键,一方定义关系
角色表:
class Role(db.Model):
__tablename__ = "roles"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
# 给Role添加关系属性users, 查询的方式: role.users
# 给User添加关系属性role, 查询的方式: user.role
users = db.relationship("User", backref="role", lazy="dynamic")
# 为了方便查看对象输出内容,重写repr
def __repr__(self):
return "<Role:%s,%s>" % (self.id, self.name)
用户表:
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
email = db.Column(db.String(32))
password = db.Column(db.String(32))
# 关键
role_id = db.Column(db.Integer, db.ForeignKey(Role.id))
# 为了方便查看对象输出内容,重写repr
def __repr__(self):
return "<User:%s,%s,%s,%s>" % (self.id, self.name, self.email, self.password)
用户表通过外键绑定角色表,从而知道用户的角色,设置relationship关联后,可以直接通过属性访问。
格式: users = db.relationship("User", backref="role", lazy="dynamic")
参数 | 描述 |
---|---|
users | 可以设置任意字符串,设置后users为角色类的一个属性,role.users可直接访问用户表中与role对象相关联的数据(role.users可查看角色为role的用户) |
backref | 设置反向关联属性,role也会成为用户类的一个属性,user.role可直接访问角色表中与user对象相关联的数据(user.role可查看用户user的角色) |
lazy | 使⽤关系属性之后,默认会做⼦查询(不管⽤不⽤的到都会查询), 可以将lazy设置动态查询 |
默认: lazy = “subquery”,不管⽤不⽤的到都会查询
建议设置: lazy = “dynamic”,只有⽤到了才去查
格式:关联属性 = db.relationship(连接的数据库类名, backref=反向绑定属性)
(1)原始写法:
user = User.query.get(1)
role = Role.query.get(user.role_id)
(2)快速查询方式:
users = db.relationship("User",backref="role")
(设置后可通过users属性直接访问连接的User属性)
user = User.query.get(1)
role = user.role
2.多对多:
多对多需要创建一个中间表,将两张表的主键存储为中间表的外键进行连接。
中间表格式:
表名称 = db.Table( "表名称",字段1,字段2 )
其中一方表:
db.relationship("模型类名",backref="属性",secondary="中间表名")
例:
#学生,课程,中间表
student_course_tb = db.Table(
"student_course_tb",
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(32))
#关系属性
courses = db.relationship("Course",backref="students",secondary="student_course_tb")
#为了方便,查看对象输出内容
def __repr__(self):
return "<Student:%s,%s>"%(self.id,self.name)
#课程模型
class Course(db.Model):
__tablename__ = "courses"
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(32))
#为了方便,查看对象输出内容
def __repr__(self):
return "<Class:%s,%s>"%(self.id,self.name)
Student对象.courses可访问关联的课程,Course对象.students可访问选该课的学生
1.目的:备份表的结构
2.过程:
(1)安装扩展:
pip install flask_migrate
pip install flask_script
(2)导入类:
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
Manager:管理app
Migrate:关联app,db
MigrateCommand:用manager添加操作命令使用MigrateCommand进行迁移(manager.add_command(“db”,MigrateCommand))
(3)终端指令:
⽣成迁移⽂件 (⼀次就好)
python xxx.py db init
将模型类,⽣成迁移脚本 (重复执⾏)
python xxx.py db migrate -m '注释'
将迁移脚本更新到数据库 (重复执⾏)
python xxx.py db upgrade / downgrade [version]
查看所有的版本号
pythoh xxx.py db history
查看当前版本号
python xxx.py db current
3.注意点:
(1)数据库迁移是为了备份表结构,⽽不是数据
(2)如果要备份数据,需要使⽤⼯具, ⽐如: navicat, mysqlworkbench等等⼯具
(3)如果进⾏降级的时候,会丢失数据,所以谨慎操作. 升级不会
例:
from flask import Flask
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库配置信息
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:zsh123@localhost:3306/basic12"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 创建SQLAlchemy对象,关联app
db = SQLAlchemy(app)
# 通过Manager管理app
manager = Manager(app)
# - 使用Migrate,关联app,db
Migrate(app, db)
# 给manager添加操作命令,使用MigrateCommand
manager.add_command("db", MigrateCommand)
# 模型类
class Student(db.Model):
__tablename__ = "students"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
age = db.Column(db.Integer)
@app.route('/')
def hello_world():
return "helloworld"
if __name__ == '__main__':
manager.run()
1.目的: 为模块化开发⽽⽣
2.优点:弱耦合
实际开发中会用很多视图和很多种类的视图,写在一个文件中耦合度太高,所以使用可以使用蓝图分多模块编写代码,然后将每个模块的蓝图对象在app上注册。
3.操作步骤:
(1)导入蓝图:
from flask import Blueprint
(2)创建蓝图对象:
blue = Blueprint("蓝图名称",__name__)
可选参数:
static_folder: 静态⽂件夹
url_prefix: 蓝图资源访问前缀
template_folder: 蓝图模板⽂件夹
(3)使⽤蓝图装饰视图函数
@blue.route("/路径")
(4)将蓝图对象注册到app
app.register_blueprint(blue)