flask-sqlalchemy操作mysql

文章目录

  • 1、简介
  • 2、mysql连接设置
  • 3、模型类字段类型
  • 4、ORM使用方式
    • 4.1、先创建模型类,再迁移到数据库
    • 4.2、用原生SQL创建数据库表,再编写模型类作映射
  • 5、CRUD
    • 5.1、增
    • 5.2、查
      • 常规查询
      • 逻辑查询
      • offset 偏移查询
      • limit
      • order_by
      • load_only 指定字段查询
      • 分组聚合
      • 复合查询
      • 多表关联查询
      • 关联字段联合查询
    • 5.3、改
    • 5.4、删
  • 6、事务

1、简介

SQLAlchemy是Python编程语言下的一款开源软件。提供了SQL工具包及对象关系映射(ORM)工具。
而Flask-SQLAlchemy是Flask对SQLAlchemy进行了一个封装,目的于简化在Flask中SQLAlchemy的使用,
提供了有用的默认值和额外的助手来更简单地完成日常任务。

orm作用
	1.省去自己拼写SQL,保证SQL语法的正确性一次编写可以适配多个数据库.
	2.防止注入攻击.
	3.在数据库表名或字段名发生变化时,只需修改模型类的映射,无需修改数据库操作的代码.
#安装Flask-SQLAlchemy和MySQL的Python客户端库以及数据库迁移工具
pip install flask-sqlalchemy
pip install mysqlclient
pip install flask_script
pip install flask_migrate ---2.7.0

2、mysql连接设置

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate,MigrateCommand#MigrateCommand在flask_migrate3.0以上已经去掉了
import pymysql
pymysql.install_as_MySQLdb()

#配置对象
class DatabaseConfig():
	#连接的数据库 URI 
	#mysql://用户名:密码@host:port/database
    SQLALCHEMY_DATABASE_URI = 
    'mysql://root:[email protected]:3306/sqlalchemyTest'
    #是否追踪数据的修改
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    #是否显示生成sql语句
    SQLALCHEMY_ECHO = False

#实例化一个flask对象
app = Flask(__name__)
#实例化一个Manager对象,flask脚本管理对象
manager = Manager(app)

#从配置对象中加载
app.config.from_object(DatabaseConfig)

#创建SQLAlchemy对象
db  = SQLAlchemy(app)
Migrate(app,db)
#将db添加进manager中
manager.add_command("db",MigrateCommand)

#或者下面这种方法创建sqlalchemy对象,但是单独运行调试时,对数据库操作需要在Flask的应用上下文中进行
#db = SQLAlchemy()
#db.init_app(app)
#with app.app_context():
#      database.query.all()

3、模型类字段类型

类型名 mysql中类型 说明
Integer int 普通整数
SmallInteger tinyint 范围小的整数
BigInteger bigint 不限精度的整数
Float float 浮点数
Numeric decimal 普通整数
String varchar 边长字符串
Date date 时间
Time datetime 日期时间
Enum enum 枚举值

4、ORM使用方式

4.1、先创建模型类,再迁移到数据库

优点:简单快捷,不用写sql
缺点:表结构发生变化的时候,容易发生迁移错误

sql_test.py

from main import db
from main import manager

class Student(db.Model):
	#设置数据库中真实表名
    __tablename__ = "student"
    
    sid = db.Column("sid",db.Integer,primary_key=True,doc="学生id")
    sname = db.Column("sname",db.String(4),nullable=False,doc="姓名")
    gender = db.Column(db.Enum("男","女"),doc="性别")
    phone = db.Column(db.String(11),nullable=False,doc="手机号")
    #第一种关联表:relationship关联表,backref添加反向引用,通过Grade对象.stu获得student表信息
 1. grades = db.relationship("Grade",backref="stu")
    #第二种关联方式:primaryjoin
 2. grades =db.relationship("Grade",primaryjoin="Student.sid==foreign(Grade.student)",backref="stu")
    #多对多关系中中间表的数据库名字,可通过student对象.courses获取课程表信息,backref同上述一样。
    courses = db.relationship("Course",secondary="student_course",backref="stu")
	#将对象转化为字符串
    def __repr__(self):
        sname = self.sname
        phone = self.phone
        return f"{sname}:{phone}"

class StudentCourse(db.Model):
    id = db.Column(db.Integer,primary_key=True,doc="学生课程id")
    sid = db.Column(db.Integer,db.ForeignKey("student.sid"),doc="学生id")
    cid = db.Column(db.Integer,db.ForeignKey("course.cid"),doc="课程id")

class Course(db.Model):
    __tablename__ = "course"

    cid = db.Column("cid",db.Integer,primary_key=True,doc="课程id")
    cname = db.Column("cname",db.String(4),nullable=False,doc="课程名")
    teacher = db.Column("teacher",db.Integer,db.ForeignKey("teacher.tid"),doc="老师id")
    grade = db.relationship("Grade",backref="cour")

class Teacher(db.Model):
    __tablename__ = "teacher"

    tid = db.Column(db.Integer,primary_key=True,doc = "老师id")
    tname = db.Column(db.String(4),nullable=False,doc="老师姓名")
    gender = db.Column(db.Enum("男", "女"), doc="性别")
    phone = db.Column(db.String(11), nullable=False, doc="手机号")
    # course = db.relationship("Course",backref="tea")
    # uselist如果为False,不使用列表,而使用标量值,使用在一对一表中
    course = db.relationship("Course",primaryjoin="Teacher.tid==foreign(Course.teacher)", backref="tea",uselist=False)

class Grade(db.Model):
    __tablename__ = "grade"

    id = db.Column(db.Integer,primary_key=True,doc="分数id")
    score = db.Column(db.Float,default=0,doc="分数")
    student = db.Column("student",db.Integer,db.ForeignKey("student.sid"),doc="学生id")
    course = db.Column("course",db.Integer,db.ForeignKey("course.cid"),doc="课程id")
if __name__ == '__main__':
#第一种更新和创建数据库,这种会清空数据数据
    db.create_all() #创建表
    #db.drop_all()   #删除表
    #第二种方法执行命令
    #manager.run()
# 第二种利用flask_migrate数据库迁移,终端上,当前文件目录下执行:
	# python sql_test.py db init  创建migrations文件夹,所有迁移文件放在这文件夹内
	#python sql_test.py db migrate 生成迁移脚本,类似django的makemigrations
	#python sql_test.py db upgrade 更新数据库  , 类似django的migrate

4.2、用原生SQL创建数据库表,再编写模型类作映射

优点:可以很好的控制数据库表结构,避免发生迁移错误
缺点:需要编写sql语句

先创建数据库表,然后编写模型类

create table student(
    id int primary key auto_increment comment "学生id",
    sname varchar(4) not null comment "姓名",
    gender enum("男","女") default "男" comment "性别",
    phone char(11) not null comment "手机号"
) engine="innodb",charset="utf8",comment="学生表";

create table teacher(
    id int primary key auto_increment comment "老师id",
    tname varchar(4) not null comment "老师姓名",
    gender enum("男","女") default "男" comment "性别",
    phone char(11) not null comment "手机号"
) engine="innodb" default charset=utf8 comment="教师表";

create table course(
    id int primary  key auto_increment comment "课程id",
    cname varchar(10) not null comment "课程名",
    teacher int default null comment "老师id",
    constraint c_t_key foreign key(teacher) references teacher(id)
) engine="innodb" default charset=utf8 comment="课程表";

create table grade(
    id int primary key auto_increment comment "分数id",
    score float default 0 comment "分数",
    student int default null comment "学生id",
    course int default null comment "课程id",
    constraint g_s_key foreign key(student) references student(id),
    constraint g_c_key foreign key(course) references course(id)
) engine="innodb" default charset=utf8 comment "分数表";

create table student_course(
    id int primary  key auto_increment comment "学生课程id",
    sid int default null comment "学生id",
    cid int default null comment "课程id",
    constraint s_s_c foreign key(sid) references student(id),
    constraint c_s_c foreign key(cid) references course(id)
) engine="innodb" default charset=utf8 comment="学生课程表";

5、CRUD

5.1、增

# 单个新增
student = Student(sname = "张三",gender="男",phone="19971251765")
db.session.add(student)
db.session.commit()
# 通过add_all([])批量新增
s1 = Student(sname = "李四",gender="男",phone="19971251766")
s2 = Student(sname = "王五",gender="男",phone="19971251767")
s3 = Student(sname = "赵六",gender="女",phone="19971251768")
s4 = Student(sname = "刘七",gender="男",phone="19971251769")
db.session.add_all([s1,s2,s3,s4])
db.session.commit()

5.2、查

常规查询

#返回所有student对象
s = Student.query.all()
#根据主键ID获取对象,若主键不存在返回None
s = Student.query.get(1)
# 返回第一个学生对象
s = Student.query.first()
#条件查询  filter 和 filter_by
s = Student.query.filter_by(gender="男").first()
ss = Student.query.filter_by(gender="男").all()
s = Student.query.filter(Student.gender=="女").first()

逻辑查询

# 逻辑或查询
from sqlalchemy import or_
User.query.filter(or_(Student.sname=='张三', Student.age==20)).all()
# 逻辑与查询
from sqlalchemy import and_
User.query.filter(and_(Student.sname=='张三', Student.age==20)).all()
# 逻辑非查询
from sqlalchemy import not_
User.query.filter(not_(Student.sname=='张三', Student.age==20)).all()

offset 偏移查询

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

limit

s = Student.query.limit(3).all()

order_by

s = Student.query.order_by(Student.sid).all()  # 正序
s = Student.query.order_by(Student.sid.desc()).all()  # 倒序

load_only 指定字段查询

from sqlalchemy.orm import load_only
User.query.options(load_only(Student.sname, Student.age)).filter_by(sid=1).first() # 查询特定字段

分组聚合

from sqlalchemy import func
#  对分数表的学生id进行分组, 求学生个数
db.session.query(Grade.student, func.count(Grade.student)).filter(Grade.score>=60).group_by(Grade.student).all()

复合查询

#查询学生年龄大于20岁,并按照id降序排列,从第二个开始,查出5个
Student.query.filter(Student.age > 20).order_by(Student.sid.desc()).offset(2).limit(5).all()

多表关联查询

# 一(课程表)对一(教师)
class Course(db.Model):
    teacher = db.Column("teacher",db.Integer,db.ForeignKey("teacher.tid"),doc="老师id")

class Teacher(db.Model):
    course = db.relationship("Course",backref="tea",uselist=False)

#通过课程表查询老师信息
c = Course.query.first()
t = c.tea  # tea 由backref指定
#通过老师表查询课程信息
t = Teacher.query.first()
c = t.course
# 一(学生)对多(分数)
class Student(db.Model):
    grades = db.relationship("Grade",backref="stu")
    
class Grade(db.Model):
    student = db.Column("student",db.Integer,db.ForeignKey("student.sid"),doc="学生id")
#通过分数查学生
g = Grade.query.first()
s = g.stu
#通过学生查分数
s = Student.query.first()
g = s.grades(列表)
# 多(学生)对多(课程)
class Student(db.Model):
    courses = db.relationship("Course",secondary="student_course",backref="stu")
#中间表
class StudentCourse(db.Model):
    sid = db.Column(db.Integer,db.ForeignKey("student.sid"),doc="学生id")
    cid = db.Column(db.Integer,db.ForeignKey("course.cid"),doc="课程id")

class Course(db.Model):
    ... ...

 s = Student.query.first()
 cs = s.courses  (列表)
 for c in cs:
     for stu in c.stu:
         print(stu.sname)
 t = Teacher.query.first()
 c = t.course

关联字段联合查询

# mysql 连表查询
from sqlalchemy.orm import load_only,contains_eager

s = Teacher.query.join(Teacher.course).options(load_only(Teacher.tname),contains_eager(Teacher.course).load_only(Course.cname)).first()
print(s.tname,s.course.cname)

5.3、改

# 第一种
c = Student.query.filter(Student.sname=="张三").update({"sname":"章三"})
db.session.commit()
#第二种
stu = Student.query.filter_by(sname="章三").first()
stu.sname = "张三"
db.session.add(stu)
db.session.commit()

5.4、删

 Student.query.filter(Student.sid == 1).delete()
  db.session.commit()

6、事务

try:
    teacher = Teacher(tname='老王',gender="男",phone="12345678910")
    db.session.add(teacher)
    db.session.flush() # 将db.session记录的sql传到数据库中执行
    course = Course(cname="数学",teacher=teacher.tid)
    db.session.add(course)
    db.session.commit()
except:
    db.session.rollback()

你可能感兴趣的:(数据库,flask,mysql,python)