1. ORM
object-relation mapping,即兑现关系映射, 实现Python 模型对象对关系型数据库的映射
- 优点
- 只用 Python 面向对象操作,不需要用 SQL 语言
- 实现了数据模型与数据库的解耦,实现了不同数据库相同操作
- 缺点
-
Python 语言与 SQL 语言相互转换,性能慢
-
不同的 ORM 之间操作不同
-
2. Flask-SQLAlchemy
是一个关系型数据库框架,提供了高层 ORM 与底层的原生数据库操作。
2.1 安装
flask-sqlalchemy 安装(清华源)
pip install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple --user
复制代码
如果使用 MySQL 数据库,需要安装 MySQLdb 驱动
pip install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
复制代码
2.2 数据库连接设置
class Config(object):
DEBUG = True
# 数据库连接配置
# SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4"
SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
复制代码
创建数据库
mysql -uroot -p123
create database students charset=utf8mb4;
复制代码
2.3 SQLAlchemy字段类型 和约束类型
字段类型
- integer 普通整型
- smallinteger
- biginteger
- float
- numeric
- string
- text
- unicode
- unicodetext
- boolean
- date
- time
- largebinary
约束类型
- primary_key
- unique
- index
- nullable
- default
2.4 数据表的操作
1 创建表
from flask import Flask
app = Flask(__name__)
class Config(object):
DEBUG = True
SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4"
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
"""模型类定义"""
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app=app)
# 所有的模型必须直接或间接继承于db.Model
class Student(db.Model):
"""学生信息模型"""
# 声明与当前模型绑定的数据表名称
__tablename__ = "db_students"
# 字段定义
id = db.Column(db.Integer, primary_key=True,comment="主键")
name = db.Column(db.String(15), comment="姓名")
age = db.Column(db.SmallInteger, comment="年龄")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(128), unique=True, comment="邮箱地址")
money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包")
def __repr__(self):
return f"{self.name}<Student>"
class Course(db.Model):
"""课程数据模型"""
__tablename__ = "db_course"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(64), unique=True, comment="课程")
price = db.Column(db.Numeric(7, 2))
# repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
def __repr__(self):
return f'{self.name}<Course>'
class Teacher(db.Model):
"""老师数据模型"""
__tablename__ = "db_teacher"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(64), unique=True, comment="姓名")
option = db.Column(db.Enum("讲师", "助教", "班主任"), default="讲师")
def __repr__(self):
return f"{self.name}< Teacher >"
@app.route("/")
def index():
return "ok!"
if __name__ == '__main__':
with app.app_context():
# 检测数据库中是否存在和模型匹配的数据表。
# 如果没有,则根据模型转换的建表语句进行建表。
# 如果找到,则不会进行额外处理
db.create_all()
app.run(debug=True)
复制代码
with app.app_context():
# create_all()方法执行的时候,需要放在模型的后面
# 检测数据库中是否存在和模型匹配的数据表。
# 如果没有,则根据模型转换的建表语句进行建表。
# 如果找到,则不会进行额外处理
db.create_all()
复制代码
2 删除表
db.drop_all()
if __name__ == '__main__':
with app.app_context():
# db.drop_all()
# 检测数据库中是否存在和模型匹配的数据表。
# 如果没有,则根据模型转换的建表语句进行建表。
# 如果找到,则不会进行额外处理
db.create_all()
app.run(debug=True)
复制代码
2.5 数据操作
1 创建一条数据
方法 1:
# 在 student 类中执行
@classmethod
def add(cls):
student = cls(name="小明", sex=True, age=17, email="123456@qq.com", money=100)
db.session.add(student)
db.session.commit()
return student
复制代码
方法 2:Student.add()
@app.route("/add")
def add():
"""添加一条数据"""
student = Student.add()
print(student)
student = Student(name="小红",age=18,sex=False, email="xiaohong@qq.com", money=1000)
db.session.add(student)
db.session.commit()
return "ok!"
复制代码
2 创建多条数据
- add_all() 方法
@app.route("/add_all")
def add_all():
"""添加多条数据"""
st1 = Student(name='wang', email='wang@163.com', age=22, money=1000, sex=True)
st2 = Student(name='zhang', email='zhang@189.com', age=22, money=1000, sex=True)
st3 = Student(name='chen', email='chen@126.com', age=22, money=1000, sex=True)
st4 = Student(name='zhou', email='zhou@163.com', age=22, money=1000, sex=True)
st5 = Student(name='tang', email='tang@163.com', age=22, money=1000, sex=True)
st6 = Student(name='wu', email='wu@gmail.com', age=22, money=1000, sex=True)
st7 = Student(name='qian', email='qian@gmail.com', age=22, money=1000, sex=True)
st8 = Student(name='liu', email='liu@163.com', age=22, money=1000, sex=True)
st9 = Student(name='li', email='li@163.com', age=22, money=1000, sex=True)
st10 = Student(name='sun', email='sun@163.com', age=22, money=1000, sex=True)
db.session.add_all([st1,st2,st3,st4,st5,st6,st7,st8,st9,st10])
db.session.commit()
return "ok"
复制代码
3 删除数据
@app.route("/delete")
def delete():
"""删除数据"""
# 先查询出来
student = Student.query.first()
print(student)
# 再进行删除
db.session.delete(student)
db.session.commit()
# 直接条件删除[ 性能更好!!! ]
Student.query.filter(Student.id > 5).delete()
db.session.commit()
return "ok"
复制代码
4 更新数据
@app.route("/update")
def update():
"""更新数据"""
# 先查询数据,然后进行更新,2条语句
stu = Student.query.first()
stu.name = 'dong'
db.session.commit()
# 直接根据条件更新,一条语句[乐观锁]
Student.query.filter(Student.name == 'chen').update({'money': 1998})
db.session.commit()
# 字段引用[利用当前一条数据的字典值进行辅助操作,实现类似django里面F函数的效果]
Student.query.filter(Student.name == "zhang").update({"money":Student.money+1000 * Student.age})
db.session.commit()
return "ok"
复制代码
总代码
from flask import Flask
app = Flask(__name__)
class Config(object):
DEBUG = True
SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
"""模型类定义"""
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app=app)
class Student(db.Model):
__tablename__ = "db_students"
id = db.Column(db.Integer, primary_key=True,comment="主键")
name = db.Column(db.String(15), comment="姓名")
age = db.Column(db.SmallInteger, comment="年龄")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(128), unique=True, comment="邮箱地址")
money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包")
def __repr__(self):
return f"{self.name}<Student>"
@classmethod
def add(cls):
student = cls(name="小明", sex=True, age=17, email="123456@qq.com", money=100)
db.session.add(student)
db.session.commit()
return student
# 所有的模型必须直接或间接继承于db.Model
class Course(db.Model):
"""课程数据模型"""
__tablename__ = "db_course"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(64), unique=True, comment="课程")
price = db.Column(db.Numeric(7, 2))
# repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
def __repr__(self):
return f'{self.name}<Course>'
class Teacher(db.Model):
"""老师数据模型"""
__tablename__ = "db_teacher"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(64), unique=True, comment="姓名")
option = db.Column(db.Enum("讲师", "助教", "班主任"), default="讲师")
def __repr__(self):
return f"{self.name}< Teacher >"
@app.route("/add")
def add():
"""添加一条数据"""
# student = Student.add()
# print(student)
# student = Student(name="小红",age=18,sex=False, email="xiaohong@qq.com", money=1000)
# db.session.add(student)
# db.session.commit()
return "ok!"
@app.route("/add_all")
def add_all():
"""添加多条数据"""
st1 = Student(name='wang', email='wang@163.com', age=22, money=1000, sex=True)
st2 = Student(name='zhang', email='zhang@189.com', age=22, money=1000, sex=True)
st3 = Student(name='chen', email='chen@126.com', age=22, money=1000, sex=True)
st4 = Student(name='zhou', email='zhou@163.com', age=22, money=1000, sex=True)
st5 = Student(name='tang', email='tang@163.com', age=22, money=1000, sex=True)
st6 = Student(name='wu', email='wu@gmail.com', age=22, money=1000, sex=True)
st7 = Student(name='qian', email='qian@gmail.com', age=22, money=1000, sex=True)
st8 = Student(name='liu', email='liu@163.com', age=22, money=1000, sex=True)
st9 = Student(name='li', email='li@163.com', age=22, money=1000, sex=True)
st10 = Student(name='sun', email='sun@163.com', age=22, money=1000, sex=True)
db.session.add_all([st1,st2,st3,st4,st5,st6,st7,st8,st9,st10])
db.session.commit()
return "ok"
@app.route("/delete")
def delete():
"""删除数据"""
# 先查询出来
student = Student.query.first()
print(student)
# 再进行删除
db.session.delete(student)
db.session.commit()
# 直接条件删除[ 性能更好!!! ]
Student.query.filter(Student.id > 5).delete()
db.session.commit()
return "ok"
@app.route("/update")
def update():
"""更新数据"""
# 先查询数据,然后进行更新,2条语句
stu = Student.query.first()
stu.name = 'dong'
db.session.commit()
# 直接根据条件更新,一条语句[乐观锁]
Student.query.filter(Student.name == 'chen').update({'money': 1998})
db.session.commit()
# 字段引用[利用当前一条数据的字典值进行辅助操作,实现类似django里面F函数的效果]
Student.query.filter(Student.name == "zhang").update({"money":Student.money+1000 * Student.age})
db.session.commit()
return "ok"
@app.route("/get")
def get():
# 根据主键获取一条数据
student = Student.query.get(4)
print(student)
# # 返回所有结果数据数据
# student_list = Student.query.all()
# print(student_list)
# # 返回第一个结果数据
# first_student = Student.query.filter(Student.id<5).first()
# print(first_student)
# 返回结果的数量
ret = Student.query.filter(Student.id<5).count()
print(ret)
return "ok"
if __name__ == '__main__':
with app.app_context():
# 检测数据库中是否存在和模型匹配的数据表。
# 如果没有,则根据模型转换的建表语句进行建表。
# 如果找到,则不会进行额外处理
db.create_all()
app.run(debug=True)
复制代码
2.6 数据的查询
查询过滤器
过滤器 | 说明 |
---|---|
filter() | 把过滤器添加到原查询上,返回一个新查询 |
filter_by() | 把等值过滤器添加到原查询上,返回一个新查询 |
limit() | 使用指定的值限定原查询返回的结果数量 |
offset() | 设置结果范围的开始位置,偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对原查询结果进行排序,返回一个新查询 |
group_by() | 根据指定条件对原查询结果进行分组,返回一个新查询 |
查询结果的方法
方法 | 说明 |
---|---|
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如果未查到,返回None |
first_or_404() | 返回查询的第一个结果,如果未查到,返回404 |
get() | 返回指定主键对应的行,如不存在,返回None |
get_or_404() | 返回指定主键对应的行,如不存在,返回404 |
count() | 返回查询结果的数量 |
paginate() | 返回一个Paginate分页器对象,它包含指定范围内的结果 |
having | 返回结果中符合条件的数据,必须跟在group by后面,其他地方无法使用。 |
@app.route("/get")
def get():
# 根据主键获取一条数据
student = Student.query.get(4)
print(student)
# 返回所有结果数据数据
student_list = Student.query.all()
print(student_list)
# 返回第一个结果数据
first_student = Student.query.filter(Student.id<5).first()
print(first_student)
# 返回结果的数量
ret = Student.query.filter(Student.id<5).count()
print(ret)
return "ok"
复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
class Config(object):
DEBUG = True
# 数据库连接配置
# SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4"
SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
"""模型类定义"""
db = SQLAlchemy(app=app)
# 等同于
# db = SQLAlchemy()
# db.init_app(app)
class Student(db.Model):
"""学生信息模型"""
# 声明与当前模型绑定的数据表名称
__tablename__ = "db_students"
# 字段定义
"""
create table db_student(
id int primary key auto_increment comment="主键",
name varchar(15) comment="姓名",
)
"""
id = db.Column(db.Integer, primary_key=True,comment="主键")
name = db.Column(db.String(15), comment="姓名")
age = db.Column(db.SmallInteger, comment="年龄")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(128), unique=True, comment="邮箱地址")
money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包")
def __repr__(self):
return f"{self.name}<Student>"
@classmethod
def add(cls):
student = cls(name="小明", sex=True, age=17, email="123456@qq.com", money=100)
db.session.add(student)
db.session.commit()
return student
# 所有的模型必须直接或间接继承于db.Model
class Course(db.Model):
"""课程数据模型"""
__tablename__ = "db_course"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(64), unique=True, comment="课程")
price = db.Column(db.Numeric(7, 2))
# repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
def __repr__(self):
return f'{self.name}<Course>'
class Teacher(db.Model):
"""老师数据模型"""
__tablename__ = "db_teacher"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(64), unique=True, comment="姓名")
option = db.Column(db.Enum("讲师", "助教", "班主任"), default="讲师")
def __repr__(self):
return f"{self.name}< Teacher >"
@app.route("/filter")
def filter():
# 模糊查询
# 使用163邮箱的所有用户
student_list = Student.query.filter(Student.email.endswith("@163.com")).all()
print(student_list)
# 姓名以"zh"开头的
student_list = Student.query.filter(Student.name.startswith("zh")).all()
print(student_list)
# 名字中带有"a"字母的数据
student_list = Student.query.filter(Student.name.contains("a")).all()
print(student_list)
# 条件比较
student_list = Student.query.filter(Student.age>18).all()
print(student_list)
# 多条件比较
# 要求多个条件都要满足
student_list = Student.query.filter(Student.age>18, Student.sex==True).all()
print(student_list)
return "ok"
@app.route("/filter_by")
def filter_by():
"""filter_by判断值相等情况"""
# 单条件
student_list = Student.query.filter_by(age=22).all()
print(student_list)
# 多条件
student_list = Student.query.filter_by(age=22,sex=True).all()
print(student_list)
return "ok"
from sqlalchemy import and_,or_,not_
@app.route("/")
def multi():
"""filter多条件运算方法"""
"""and_ 与,并且的意思,必须所有条件都满足则返回结果"""
# and_(条件1,条件2,....) 等价于 filter(条件1,条件2,.....)
# age > 18 and email like "%163.com"
# student_list = Student.query.filter(Student.age > 18, Student.email.endswith("163.com")).all()
student_list = Student.query.filter(
and_(
Student.age > 18,
Student.email.endswith("163.com")
)
).all()
"""or_ 或,或者的意思,多个条件只有一个满足则返回结果"""
# 查询性别为True,或者年龄大于18
sex = 1 or age > 18
student_list = Student.query.filter(
or_(
Student.sex==True,
Student.age>18
)
).all()
print(student_list)
# 复合条件的查询情况
# 查询18岁的女生或者22岁的男生
# (age=18 and sex=0) or (age = 22 and sex=1)
student_list = Student.query.filter(
or_(
and_(Student.age==18, Student.sex==False),
and_(Student.age==22, Student.sex==True),
)
).all()
print( student_list )
# not_ 非,结果取反
# 查询年龄不等于22
student_list = Student.query.filter(Student.age != 22).all()
print(student_list)
student_list = Student.query.filter(not_(Student.age==22)).all()
print(student_list)
return "ok"
if __name__ == '__main__':
with app.app_context():
# 检测数据库中是否存在和模型匹配的数据表。
# 如果没有,则根据模型转换的建表语句进行建表。
# 如果找到,则不会进行额外处理
db.create_all()
app.run(debug=True)
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END