安装
pip install flask-sqlalchemy
windows如果出现安装错误:ERROR: Cannot unpack file xxxx,使用下面命令安装成功
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn flask-sqlalchemy
简单入门
init.py:初始化的文件
insertUserTable.py:创建所有的表,插入用户数据,查询用户数据
# init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import sys
import os
app = Flask(__name__)
# 创建数据库,并连接flask程序
WIN = sys.platform.startswith('win')
if WIN:
prefix = 'sqlite:///'
else:
prefix = 'sqlite:////'
dev_db = prefix + os.path.join(os.path.dirname(app.root_path), 'data.db')
print("dev_db:", dev_db)
app.config['SQLALCHEMY_DATABASE_URI'] = dev_db
app.config['SECRET_KEY'] = 'secret string'
# 设置每次请求结束后会自动提交数据库的改动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 查询时显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# 声明用户表
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
# 此方法是实例化对象的自我描述信息,相当于java的toString(),默认情况下返回:类名+object at 内存地址
def __repr__(self):
return '<User: %s %s >' % (self.username, self.email)
# insertUserTable.py
from demo.init import db, User
'''
创建用户数据并插入用户表,然后查询用户表中的数据
'''
db.drop_all() # 删除所有的表
db.create_all() # 创建所有生命的表
# 创建用户数据
user1 = User('user1', 'user1@qq.com')
user2 = User(username='user2', email='user2@qq.com')
# 将创建好的用户数据插入到用户表中
db.session.add(user1)
db.session.add(user2)
db.session.commit()
# 查询用户表所有的用户数据
users = User.query.all()
print(users)
执行输出如下:
[<User: user1 user1@qq.com >, <User: user2 user2@qq.com >]
常用的sqlalchemy字段类型
类型名 | python中的类型 | 说明 |
---|---|---|
Integer | int | 整数类型,32位 |
SmallInteger | int | 取值范围小的整数,16位 |
BigInteger | int或long | 不限制精度的整数 |
Float | float | 浮点数 |
Numeric | decimal.Decimal | 整数,32位 |
String | str | 变长字符串 |
Text | str | 变长字符串,对较长或不限制长度的字符串做了优化 |
Unicode | unicode | 变长Unicode字符串 |
UnicodeText | unicode | 变长Unicode字符串,对较长或不限长度的字符串做了优化 |
Boolean | bool | 布尔值 |
Date | datetime.date | 时间 |
Time | datetime.datetime | 日期和时间 |
LargeBinary | str | 二进制文件 |
常用的列表项
选项名 | 说明 |
---|---|
primary_key | True表示表的主键 |
unique | True表示这列不允许出现重复的值 |
index | True表示为这列创建索引,提高查询效率 |
nullable | True表示允许有空值,False表示不允许有空值 |
default | 设置默认值 |
常用的关系选项
选项名 | 说明 |
---|---|
backref | 在关系的另一模型中添加反向引用 |
primary join | 明确指定两个模型之间使用的联结条件 |
uselist | 如果为False,不使用列表,而使用标量值 |
order_by | 指定关系中记录的排序方式 |
secondary | 指定多对多关系中关系表的名字 |
secondary join | 在SQLALchemy中无法自行决定时,指定多对多关系中的二级联结条件 |
flask-sqlalchemy配置项
配置项的key | 说明 |
---|---|
SQLALCHEMY_DATABASE_URI | 用于连接数据库,例如:sqlite:////tmp/test.db(linux或mac),mysql://username:password@server/db |
SQLALCHEMY_BINDS | 一个映射绑定 (bind) 键到 SQLAlchemy 连接 URIs 的字典。 更多的信息请参阅 绑定多个数据库。 |
SQLALCHEMY_ECHO | 设置成 True,显示原始SQL语句日志 |
SQLALCHEMY_POOL_SIZE | 数据库连接池的大小。默认是数据库引擎的默认值 (通常是 5) |
SQLALCHEMY_RECORD_QUERIES | 可以用于显式地禁用或者启用查询记录。查询记录 在调试或者测试模式下自动启用。更多信息请参阅 get_debug_queries() |
SQLALCHEMY_NATIVE_UNICODE | 可以用于显式地禁用支持原生的 unicode。这是 某些数据库适配器必须的(像在 Ubuntu 某些版本上的 PostgreSQL),当使用不合适的指定无编码的数据库 默认值时。 |
SQLALCHEMY_POOL_RECYCLE | 自动回收连接的秒数。这对 MySQL 是必须的,默认 情况下 MySQL 会自动移除闲置 8 小时或者以上的连接。 需要注意地是如果使用 MySQL 的话, Flask-SQLAlchemy 会自动地设置这个值为 2 小时 |
SQLALCHEMY_MAX_OVERFLOW | 控制在连接池达到最大值后可以创建的连接数。当这些额外的 连接回收到连接池后将会被断开和抛弃 |
SQLALCHEMY_TRACK_MODIFICATIONS | 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它 |
一对多关系
假设有两张表:班级表Classe和学生表Student,Classe存储班级信息,Student存储学生信息;每个班级对应多个学生,
一个学生只能对应一个班级,班级表Classe与学生表Students是一对多关系
db.relationship()关系函数定义关系属性,
这里让Classe指向Student类并加载多个,如果想要一对一关系,使用userlist=False,并设置给relationship()。
backref是在一个Student类上声明新属性的简单方法,也可以通过stu._class来获取该学生所属班级
lazy决定了SQLALCHEMY什么时候从数据库加载数据:
- select : 默认属性。按需加载,即在访问到属性的时候,才会全部加载该属性的数据
- joined : 加载记录,但使用联结
- subquery : 与joined类似,立即加载,但使用子查询。
- dynamic : 不加载记录,而是提供加载记录的查询,即生成一个query对象,方便进行条件过滤
from demo.init import db
class Student(db.Model):
__tablename__ = 'students'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), nullable=False)
# 定义外键(表明.字段名)
class_id = db.Column(db.Integer, db.ForeignKey('classes.id'))
def __repr__(self):
return '<Student: %r>' % self.name
class Classe(db.Model):
__tablename__ = 'classes'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), nullable=False)
# 使用关系函数定义关系属性
students = db.relationship('Student', backref='_class', lazy='select')
def __repr__(self):
return '<Classe %r>' % self.name
# 创建所有的表
db.create_all()
# 删除Student表和Classe表的所有行
Student.query.delete()
Classe.query.delete()
# 创建数据,并插入数据库
stu1 = Student(name='stu1')
stu2 = Student(name='stu2')
stu3 = Student(name='stu3')
class1 = Classe(name='class1', students=[stu1])
class2 = Classe(name='class2', students=[stu2, stu3])
db.session.add_all([stu1, stu2, stu3, class1, class2])
db.session.commit()
# 查询所有学生
stu_all = Student.query.all()
print('全部学生:', stu_all)
# 查询第一个学生所属班级
stu_01 = stu_all[0]
print("该学生所属班级:", stu_01._class)
# 查询二班所有的学生
stus_of_class2 = Student.query.filter_by(_class=class2).all()
print('二班的学生:', stus_of_class2)
# 查询全部班级
cls_all = Classe.query.all()
print('全部班级:', cls_all)
# 查询二班所有的学生
cls2 = Classe.query.filter_by(name='class2').first()
print('二班学生:', cls2.students)
多对多关系
假设一堆学生学习不同的课程,这就是多对多关系
多对多的关系中需要定义一个用于关系的辅助表,这个辅助表不使用模型,而是采用一个实际的表
from demo.init import db
'''
多对多关系
假设一堆学生学习不同的课程,这就是多对多关系
'''
tb_student_course = db.Table('tb_student_course',
db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
db.Column('course_id', db.Integer, db.ForeignKey('courses.id')))
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
# 关联属性,多对多的情况,可以写在任意一个模型类型中,含有正向引用和反向引用
relate_courses = db.relationship('Course',
secondary=tb_student_course,
backref='relate_student',
lazy='dynamic')
def __repr__(self):
return '<Student %r>' % self.name
class Course(db.Model):
__tablename__ = 'courses'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
def __repr__(self):
return '<Course %r>' % self.name
# 创建所有表
db.create_all()
# 删除Student表和Course表的所有行
Student.query.delete()
Course.query.delete()
# 添加数据
stu1 = Student(name='张三')
stu2 = Student(name='李四')
stu3 = Student(name='王五')
cou1 = Course(name='物理')
cou2 = Course(name='化学')
cou3 = Course(name='生物')
# 添加关系
stu1.relate_courses = [cou2, cou3]
stu2.relate_courses = [cou2]
stu3.relate_courses = [cou1, cou2, cou3]
# 添加到数据库
db.session.add_all([stu1, stu2, stu3, cou1, cou2, cou3])
db.session.commit()
# 查询张三学习的所有课程
stu = Student.query.filter_by(name='张三').first()
for course in stu.relate_courses:
print('张三学习的课程:', course.name)
# 查询学习生物这门课程的所有学生
course = Course.query.filter_by(name='生物').first()
for student in course.relate_student:
print('学习生物的学生', student.name)
操作数据库:增删改查
from demo.init import db
from sqlalchemy import and_
'''
操作数据库,增删改查
'''
class Kids(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False, unique=True)
age = db.Column(db.Integer, nullable=False)
def __repr__(self):
return '<Kids name:%r age:%r>' % (self.name, self.age)
# 查询所有的kid
def queryAllKid():
kids = Kids.query.all()
print(kids)
# 添加数据到数据库
def add_data():
kid1 = Kids(name='kid1', age=4)
kid2 = Kids(name='kid2', age=5)
kid3 = Kids(name='kid3', age=9)
kid4 = Kids(name='kid4', age=12)
kid5 = Kids(name='kid5', age=12)
kid6 = Kids(name='kid6', age=12)
db.session.add_all([kid1, kid2, kid3, kid4, kid5, kid6])
db.session.commit()
# 创建数据库表
db.create_all()
# 删除Kids表所有行
Kids.query.delete()
# ----------- 增 -------------
# 添加一条数据
kid1 = Kids(name='kid1', age=4)
db.session.add(kid1)
db.session.commit()
# 添加多条数据(添加的是数组)
kid2 = Kids(name='kid2', age=5)
kid3 = Kids(name='kid3', age=9)
kid4 = Kids(name='kid4', age=12)
db.session.add_all([kid2, kid3, kid4])
db.session.commit()
queryAllKid()
# ----------- 删 -------------
# 先查询后删除
kid_del_1 = Kids.query.filter_by(name='kid1').first()
if kid_del_1 != None:
db.session.delete(kid_del_1)
db.session.commit()
queryAllKid()
# 删除Kids表所有行
Kids.query.delete()
queryAllKid()
# ----------- 改 -------------
add_data()
# 修改,先查询后修改
kid_update_1 = Kids.query.filter_by(name='kid1').first()
if kid_update_1 != None:
kid_update_1.name = 'kid_1_update'
db.session.commit()
queryAllKid()
# ----------- 查 -------------
# 原生slq语句查询,待补充
sql = 'select * from kids'
result_1 = db.session.execute(sql)
# 查询全部
result_2 = Kids.query.all()
print('查询全部:', result_2)
# 主键查询
result_3 = Kids.query.get(1)
print('主键查询:', result_3)
# 单条件查询
result_4 = Kids.query.filter_by(name='kid2').first()
print('条件查询:', result_4)
# 多条件查询
result_5 = Kids.query.filter(and_(Kids.name == 'kid2', Kids.age == 5)).first()
print('多条件查询:', result_5)
# 比较查询 .__lt__(5):小于5,__le__(5):小于等于5,__gt__(5):大于5,__ge__(5):大于等于5
result_6 = Kids.query.filter(Kids.age.__gt__(5)).all()
print('比较查询:', result_6)
# in查询
result_7 = Kids.query.filter(Kids.name.in_(['kid1', 'kid2', 'kid3'])).all()
print('in查询:', result_7)
# 排序
result_8 = Kids.query.order_by('age').all()
print('排序:', result_8)
# 限制查询,在符合age=12的结果中,跳过一个,剩下的结果选取前2个
result_9 = Kids.query.filter_by(age=12).offset(1).limit(2).all()
print('限制查询:', result_9)
网友评论