Flask数据库模型之flask-sqlalchemy的使用(三)

一、flask-sqlalchemy的安装和配置

  sqlalchemy 是python开发的一个ORM(数据库映射)模块: 将python面向对象的类映射为数据库的表,通过映射关系来完成数据库的操作,降低数据库操作的难度和繁琐程度。类似的模块还有(peewee)。

  Flask将sqlalchemy进行封装,封装到自己的项目当中, sqlalchemy和flask-sqlalchemy的操作有一部分不同。

1、安装flask-sqlalchemy

pip install flask-sqlalchemy

在这里插入图片描述
2、连接数据库

SQLALCHEMY_DATABASE_URI  flask_sqlalchemy 配置数据连接的参数
	不同数据库连接方式不同:
		Mysql mysql://username:password@hostname[:port]/database
		
		Sqlite(windows) sqlite:///d:/python/python.sqlite
		
		Sqlite(linux) sqlite:python/python.sqlite
		
		Pgsql: postgresql://username:password@hostname/database
		
SQLALCHEMY_COMMIT_ON_TEARDOWN 请求结束后自动提交数据库修改

SQLALCHEMY_TRACK_MODIFICATIONS 如果设置成 True (默认情况),Flask-SQLAlchemy
将会追踪对象的修改并且发送信号。这需要额外的内存,如果不必要的可以禁用它。 

flask_sqlalchemy的官方配置文档

3、flask-sqlalchemy简单使用实例

import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy  # 导入flask_sqlalchemy中的SQLAlchemy

# 创建flask实例
app = Flask(__name__)

# 当前文件绝对路径,用于拼接sqlite数据库生成文件
BASE_DIR = os.path.abspath(os.path.dirname(__file__))

#app.config返回类字典对象,里面用来存放当前app实例的配置
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///"+os.path.join(BASE_DIR,"Demo.sqlite")
app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True

#关联sqlalchemy和flask应用
db = SQLAlchemy(app) 

class Student(db.Model):
    __tablename__ = "students" #表名
    id = db.Column(db.Integer,primary_key = True) #字段
    name = db.Column(db.String(32),unique = True)

models.create_all() # 创建数据表

4、flask-sqlalchemy的表字段及参数说明
创建数据表
定义类,类下需要__tablename__来定义表的名称

字段类型

Integer	        int	普通整数,一般是 32 位
SmallInteger	int	取值范围小的整数,一般是 16 位
Big Integer	    int 或 long	不限制精度的整数
Float	        float	浮点数
Numeric	        decimal.Decimal	定点数
String	        str	变长字符串
Text	        str	变长字符串,对较长或不限长度的字符串做了优化
Unicode	        unicode	变长 Unicode 字符串
UnicodeText	    unicode	变长 Unicode 字符串,对较长或不限长度的字符串做了优化
Boolean	        bool	布尔值
Date	        datetime.date	日期
Time	        datetime.time	时间
DateTime	    datetime.datetime	日期和时间
Interval	    datetime.timedelta	时间间隔
Enum	        str	一组字符串
PickleType	    任何 Python 对象	自动使用 Pickle 序列化
LargeBinary	    str	二进制文件

字段常用的参数

primary_key 主键
unique      不重复
index       索引
nullable    如果为True是可以为空
default     默认值
autoincrement 自增长

二、flask-sqlalchemy中的数据表关系

1、一对一关系
在一个表里记录另一个表的字段

2、一对多关系

使用字段类型db.Foreignkey("主键表.id")

Flask数据库模型之flask-sqlalchemy的使用(三)_第1张图片
3、多对多关系

# 关联sqlalchemy和flask应用
db = SQLAlchemy(app)

class Student(db.Model):
    """
    学生表
    """
    __tablename__ = "student"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
    gender = db.Column(db.Integer) # 1 男 0 女 -1 unknown

class Course(db.Model):
    """
    课程表
    """
    __tablename__ = "course"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32))
    description = db.Column(db.Text)

# 学生课程关联表(多对多),也可以使用下面的方式创建该表
Student_Course = db.Table(
    "student_course",
    db.Column("id",db.Integer,primary_key=True,autoincrement=True),
    db.Column("student_id",db.Integer,db.ForeignKey("student.id")),
    db.Column("course_id",db.Integer,db.ForeignKey("course.id")),
    db.Column("delete_flag",db.Integer,default=1)  # 1没有停课 0停课

)

# class Stu_Cou(db.Model):
#     """
#     课程,学员关联表
#     """
#     __tablename__ = "student_course"
#     id = db.Column(db.Integer, primary_key=True, autoincrement=True)
#     course_id = db.Column(db.Integer,db.ForeignKey("course.id"))
#     student_id = db.Column(db.Integer, db.ForeignKey("student.id"))

搭建一个学生管理系统模型:

import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

BASE_DIR = os.path.abspath(os.path.dirname(__file__))

# app.config返回类字典对象,里面用来存放当前app实例的配置
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///"+os.path.join(BASE_DIR,"Student.sqlite")
app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True

# 关联sqlalchemy和flask应用
db = SQLAlchemy(app)

class Student(db.Model):
    """
    学生表
    """
    __tablename__ = "student"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
    gender = db.Column(db.Integer) # 1 男 0 女 -1 unknown

class Course(db.Model):
    """
    课程表
    """
    __tablename__ = "course"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32))
    description = db.Column(db.Text)

# 学生课程关联表(多对多),也可以使用上面的方式创建该表
Student_Course = db.Table(
    "student_course",
    db.Column("id",db.Integer,primary_key=True,autoincrement=True),
    db.Column("student_id",db.Integer,db.ForeignKey("student.id")),
    db.Column("course_id",db.Integer,db.ForeignKey("course.id")),
    db.Column("delete_flag",db.Integer,default=1)  # 1没有停课 0停课

)

# class Stu_Cou(db.Model):
#     """
#     课程,学员关联表
#     """
#     __tablename__ = "student_course"
#     id = db.Column(db.Integer, primary_key=True, autoincrement=True)
#     course_id = db.Column(db.Integer,db.ForeignKey("course.id"))
#     student_id = db.Column(db.Integer, db.ForeignKey("student.id"))

class Grade(db.Model):
    """
    成绩表
    学生、课程关联此表
    """
    __tablename__ = "grade"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    grade = db.Column(db.Float,default=0)
    student_id = db.Column(db.Integer,db.ForeignKey("student.id"))
    course_id = db.Column(db.Integer,db.ForeignKey("course.id"))

class Attend(db.Model):
    """
    考勤表:记录学生出勤状况
    学生考勤:一对多
    """
    __tablename__ = "attend"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    att_time = db.Column(db.Date)
    status = db.Column(db.Integer,default=1) # 0 请假 ;1 正常出勤 ;2 迟到 ;3 早退 ;4 旷课
    student_id = db.Column(db.Integer,db.ForeignKey("student.id"))

class Teacher(db.Model):
    """
    老师表
    老师与课程是多对一
    """
    __tablename__ = "teacher"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
    gender = db.Column(db.Integer)# 1 男 0 女 -1 unknown
    course_id = db.Column(db.Integer,db.ForeignKey("course.id"))

db.drop_all()
db.create_all()


三、flask-sqlalchemy中的增删改查

1、新增保存数据
先创建数据会话,基于会话进行数据的增删改查
Flask数据库模型之flask-sqlalchemy的使用(三)_第2张图片

创建数据表实例,传入想要添加的数据
Flask数据库模型之flask-sqlalchemy的使用(三)_第3张图片
使用session保存数据

session.add(表实例)
session.commit()#添加后提交

Flask数据库模型之flask-sqlalchemy的使用(三)_第4张图片
在这里插入图片描述

添加传入数据的方式,不只是可以通过参数传递这一种方式,还可以像Django保存数据的方式,通过类属性方式传递;也可以使用字典解包方式传递

下面我们使用批量添加数据的方法应用这几个插入数据的方式

session.add_all([实例对象1,2,3...])
session.commit()

Flask数据库模型之flask-sqlalchemy的使用(三)_第5张图片
Flask数据库模型之flask-sqlalchemy的使用(三)_第6张图片

2、flask-sqlalchemy查询方法的使用
①all() 查询返回的所有的结果

print(Student.query.all())

Flask数据库模型之flask-sqlalchemy的使用(三)_第7张图片
②first()查询返回的第一个结果

print(Student.query.first())

Flask数据库模型之flask-sqlalchemy的使用(三)_第8张图片
③filter_by()过滤器,条件查询

# 后边必须跟all()方法,否则条件参数传不过去
print(Student.query.filter_by(age=18).all())

Flask数据库模型之flask-sqlalchemy的使用(三)_第9张图片
④filter()过滤器,条件查询,与filter_by条件使用不一样,需要类名.字段==条件进行查询

# 后边必须跟all()方法,否则条件参数传不过去
print(Student.query.filter(Student.age==18).all())

Flask数据库模型之flask-sqlalchemy的使用(三)_第10张图片
⑤order_by() 排序查询
升序查询

print(Student.query.order_by("age").all())

Flask数据库模型之flask-sqlalchemy的使用(三)_第11张图片
降序查询
使用sqlalchemy的字段desc进行降序

print(Student.query.order_by(db.desc("age")).all())

Flask数据库模型之flask-sqlalchemy的使用(三)_第12张图片

⑥get() 以主键查询

print(Student.query.get(3))

Flask数据库模型之flask-sqlalchemy的使用(三)_第13张图片

⑦offset() 偏移量 limit() 限制条数
一般offset和limit方法会结合使用

print(Student.query.offset(2).limit(2).all())

Flask数据库模型之flask-sqlalchemy的使用(三)_第14张图片

扩展
如果有offset和limit的情况下,通常会用这个方法进行分页查询
分页:
用到参数

  • page 页码 1
  • page_size 单页条数 10

如:

  • 第1页 数据 0-10
  • 第2页 数据 10-20
  • 第3页 数据 20-30
  • 第n页 数据 (n-1)page_size - n*page_size

使用offset和limit进行分页的flask使用模板:
在这里插入图片描述

3、修改数据
flask-sqlalchemy修改数据跟添加数据使用的方法一样,类似于字典的方法,进行赋值就相当于修改
先获取某一个数据,对该数据字段进行赋值,然后用session中的add方法进行更新修改提交

student = Student.query.get(4)
student.name = "唐老鸭"
session.add(student)
session.commit()

Flask数据库模型之flask-sqlalchemy的使用(三)_第15张图片
Flask数据库模型之flask-sqlalchemy的使用(三)_第16张图片

4、flask-sqlalchemy 删除数据
获取姓名为张三的数据,对其进行删除

# 删除数据
student = Student.query.filter_by(name="张三").first()
session.delete(student)
session.commit()

Flask数据库模型之flask-sqlalchemy的使用(三)_第17张图片
Flask数据库模型之flask-sqlalchemy的使用(三)_第18张图片

四、基于flask_sqlalchemy的数据库操作优化

1、结构瑕疵
flask_sqlalchemy不同于Django中的数据模型,它不会自动创建id主键,如果我们有许多数据模型,那么每一个数据模型都需要去定义一个主键字段,就很不方便,所以我们可以使用面向对象的继承方法,继承db.Model类去定义一个id主键,然后创建的所有模型都继承我们新建的模型类方法,它及拥有db.Model中的字段方法,还新增了一个id主键,不必我们每一次去定义主键

使用抽象类来定义,定义完成数据模型继承此抽象类,并删除之前的id主键字段
Flask数据库模型之flask-sqlalchemy的使用(三)_第19张图片

同时我们还可以将数据添加、修改、删除的功能定义到这个抽象模型类,那种下次添加删除数据也不需要每次都写session.add()和session.commit(),也同时实现了代码的冗余。

class BaseModel(db.Model):
    __abstract__ = True # 抽象表为True,代表当前类为抽象类,不会被创建
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    
    # 数据保存方法
    def save(self):
        session.add(self)
        session.commit()
     
     # 数据删除方法   
    def delete_data(self):
        session.delete(self)
        session.commit()

现在我们重新添加一条数据,使用该抽象类定义的方法保存和删除数据
添加数据
Flask数据库模型之flask-sqlalchemy的使用(三)_第20张图片
Flask数据库模型之flask-sqlalchemy的使用(三)_第21张图片
删除数据
Flask数据库模型之flask-sqlalchemy的使用(三)_第22张图片
Flask数据库模型之flask-sqlalchemy的使用(三)_第23张图片

2、数据映射瑕疵
flask-sqlslchemy 继承了 sqlalchemy的数据库抽象,在一对多和多对多关系当中, 需要双向映射
Flask数据库模型之flask-sqlalchemy的使用(三)_第24张图片
Flask数据库模型之flask-sqlalchemy的使用(三)_第25张图片

注意:
Sqllite数据库,在整形的orm类型可以传入字符
mysql数据库,插入非法类型,比如将字符插入整型,会直接插入0,并且进行waring警告
在这里插入图片描述

你可能感兴趣的:(Flask框架,CRUD操作)