Flask-SQLAlchemy入门

安装

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)

源码地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转载,觉得这篇写 SQLAlchemy Core,写得非常不错。不过后续他没写SQLAlchemy ORM... ...
    非梦nj阅读 5,499评论 1 14
  • SQLAlchemy学习笔记(二) SQLAlchemy Core 现在我们可以连接到数据库了,接下来让我们看看如...
    麦卡鲁阅读 1,791评论 0 2
  • SQLAlchemy介绍和基本使用 数据库时一个网站的基础,在 flask 中可以自由的使用MySQL、Postg...
    宽哥好阅读 1,289评论 0 4
  • Flask-SQLAlchemy的使用: ORM的好处:可以让我们操作数据库跟操作对象是一样的,非常方便,因为一个...
    Dozing阅读 23,384评论 3 22
  • 印象里七夕应该是异地恋人们的专属节日,对于能在这一天相聚的恋人们,七夕自然是快乐的。对于不能在这一天相聚的恋人们,...
    弋Yi莹阅读 181评论 1 3