一、配置SQLAlchemy
1.安装包
pip install flask-sqlalchemy
pip install pymysql
2.配置数据库
a)配置SQLALCHEMY_DATABASE_URI SQLALCHEMY_TRACK_MODIFICATIONS
>>>root 用户名
>>>password 密码
>>>localhost 数据库地址:本地数据库 / 服务器地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:passowrd@localhost:3306/数据库名称'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
b)初始化
SQLAlchemy(app=app)
二、model模型
1.数据类型
a)String(长度) 字符串
b)Integer 整数
c)Date 时间
2.参数
a)primary_key 主键
b)autoincrement 从1开始,每次自动增加1
c)unique 唯一
d)default 默认
e)nullable 是否允许为空值
3.创建模型
a)知识点:
>>>db = SQLAlchemy() 实例化
>>>db.Model 继承model类
>>>db.Column() 插入属性
>>>db.String(20) 数据类型
>>>__tablename__ 指定表名称
>>>def __init__(self, 参数1, 参数2) 模型初始化
初始化的作用:在创建实例时非常方便,如创建一个姓名为王小,年龄20的学生,可以直接写作:Student('王小', 20)
b)实例
创建一个学生模型,保存学生姓名、年龄信息。
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Student(db.Model):
s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
s_name = db.Column(db.String(20), unique=True)
s_age = db.Column(db.Integer, default=18)
__tablename__ = 'student'
def __init__(self, name, age):
self.s_name = name
self.s_age = age
创建一个班级模型,保存班级名称、班级描述、班级创建时间信息。
class Grade(db.Model):
g_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
g_name = db.Column(db.String(10), unique=True)
g_desc = db.Column(db.String(100),nullable=True)
g_time = db.Column(db.Date, default=datetime.now)
__tablename__ = 'grade'
def __init__(self, name, desc):
self.g_name = name
self.s_desc = desc
>>>注意:Flask中创建的模型,不会自动创建id字段,需要自己定义。
4.一对多关系
通过如下实例阐述flask中一对多关系。
实例:给上述的学生表添加一个s_grade外键,链接到班级表,指定每个学生所在的班级。
a)学生表中添加s_grade字段:
>>>必须先指定s_grade的数据类型db.Integer,再指定外键信息db.ForeignKey。
>>>db.ForeignKey(‘参数’)
参数grade.g_id含义:grade是被关联表中__tablename__ 指定的表名称,g_id是被关联表的主键名。
s_grade = db.Column(db.Integer, db.ForeignKey('grade.g_id'), nullable=True)
b)班级表中添加students字段:
在django中设置外键时只需要在要设置外键的表中添加外键,而不需要在被关联表中进行任何操作。但是在SQLAlchemy建模中,还需要在被关联的模型中添加关系。这里在Grade模型中新建了一个名叫students的属性用来表示当前班级中包含的学生列表。
格式:db.relationship(‘参数1’, backref='参数2', lazy=True)
students = db.relationship('Student', backref='stu', lazy=True)
如上所示,students被定义成一个db.relationship对象,该对象的构造函数由两部分组成:
>>>第一部分: 'Student'表示关系的另一端模型的名称.
>>>第二部分: 是一个名叫backref的参数,叫做反向关系,我们将其设置成'stu',它会像Student模型中添加一个名叫做stu的属性,这个属性可以替代s_grade访问Grade模型,但是它获取的是Grade模型的对象,而非Grade模型对应的g_id的值。
c)一对多的应用
实例1:通过学生id查询学生的信息,和该学生所在班级的信息
>>>a)视图
@grade.route('/selectgradebystu/<int:stuid>/')
def select_grade_by_stu(stuid):
stu = Student.query.get(stuid)
grade = stu.stu
return render_template('student_grade.html', stu=stu, grade=grade)
>>>b)html页面解析
{% extends 'base_main.html' %}
{% block title %}
根据学生查询班级
{% endblock %}
{% block content %}
学生编号:{{ stu.s_id }}
学生姓名:{{ stu.s_name }}
学习年龄:{{ stu.s_age }}
班级名称:{{ grade.g_name }}
{% endblock %}
>>>c)演示结果
>>>d)比对数据库
实例2:通过班级id查找班级所有学生信息
>>>a)视图
@grade.route('/selectstubygrade/<int:gradeid>/')
def select_stu_by_grade(gradeid):
grade = Grade.query.get(gradeid)
stus = grade.students
return render_template('grade_student.html', grade=grade, stus=stus)
>>>b)html页面解析
{% extends 'base_main.html' %}
{% block title %}
班级找学生
{% endblock %}
{% block content %}
班级编号:{{ grade.g_id }}
<ul>
{% for stu in stus %}
<li>
学生编号:{{ stu.s_id }}
学生姓名:{{ stu.s_name }}
学生年龄:{{ stu.s_age }}
</li>
{% endfor %}
</ul>
{% endblock %}
>>>c)演示结果
>>>d)比对数据库
知识点:
1.想通过外键所在表查询被关联表的信息,不使用外键,而是使用backref指定的名称。
2.想通过被关联表查询外键所在表信息,使用被关联表中添加的字段名称即可。
5.多对多关系
多对多关系:假设存在一个学生表,和一个课程表,一个学生可以选择多门课程,一门课程可以被多个学生选择,那么学生和课程之间就是多对多的关系。
>>>学生表
class Student(db.Model):
s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
s_name = db.Column(db.String(20), unique=True)
s_age = db.Column(db.Integer, default=18)
__tablename__ = 'student'
def __init__(self, name, age):
self.s_name = name
self.s_age = age
>>>课程表
class Course(db.Model):
c_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
c_name = db.Column(db.String(10), unique=True)
__tablename__ = 'course'
def __init__(self, name):
self.c_name = name
flask中多对多关系仍使用定义一对多关系的 db.relationship() 方法进行定义,但在多对多关系中,增加了 secondary 参数,用于指定关联表。此处的关联表是需要单独创建的一个表,不是模型,SQLAlchemy 会自动接管这个表。多对多关系可以在关联的两个类中的任何一个类中定义, backref 参数会处理好关系的另一侧。
a)创建关联表
格式:db.Table('参数1‘, db.Column('参数2', db.参数3, db.ForeignKey('参数4')))
>>>参数1:关联表的名称
>>>参数2:字段名称
>>>参数3:数据类型
>>>参数4:外键名称,格式和一对多中格式相同
sc = db.Table('sc',
db.Column('s_id', db.Integer, db.ForeignKey('student.s_id'), primary_key=True),
db.Column('c_id', db.Integer, db.ForeignKey('course.c_id'), primary_key=True)
)
b)在任意一个类中添加字段:
格式:db.relationship('参数1', secondary=参数2, backref='参数3')
>>>参数1:关联的另一个类名称
>>>参数2:关联表的表名称
>>>参数3:想要用另一个类调用这个类的信息时,就需要使用此参数,参数名称可自行定义。
如下在课程表中添加students字段,相当于给课程表添加了students属性,通过这个属性可以获取学生的信息,并且学生可以通过cou属性获取课程信息。
students = db.relationship('Student', secondary=sc, backref='cou')
c)多对多的应用
实例1:添加学生选课信息,一次只添加一门课程
>>>a)视图
@stu.route('/stucou/', methods=['GET', 'POST'])
def stu_cou():
if request.method == 'GET':
stus = Student.query.all()
cous = Course.query.all()
return render_template('stu_cou.html', stus=stus, cous=cous)
else:
s_id = request.form.get('student')
c_id = request.form.get('course')
stu = Student.query.get(s_id)
cou = Course.query.get(c_id)
cou.students.append(stu)
db.session.add(cou)
db.session.commit()
return '学生选课成功'
>>>b)html页面解析
{% extends 'base_main.html' %}
{% block title %}
学生课程信息
{% endblock %}
{% block extCSS %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/h3.css') }}">
{% endblock %}
{% block content %}
<form action="" method="post">
<h3>学生1信息:</h3>
<br>
<select name="student" id="">
<option value="">请选择学生信息</option>
{% for stu in stus %}
<option value="{{ stu.s_id }}">{{ stu.s_name }}</option>
{% endfor %}
</select>
<br>
<h3>课程信息:</h3>
<select name="course" id="">
<option value="">请选择课程信息</option>
{% for cou in cous %}
<option value="{{ cou.c_id }}">{{ cou.c_name }}</option>
{% endfor %}
</select>
<br>
<input type="submit" value="提交">
</form>
{% endblock %}
>>>c)演示结果
>>>d)比对数据库
点击提交,会在数据库sc表中创建一条记录
实例2:添加学生选课信息,一次添加多门课程
>>>a)视图
@stu.route('/stucou/', methods=['GET', 'POST'])
def stu_cou():
if request.method == 'GET':
stus = Student.query.all()
cous = Course.query.all()
return render_template('stu_cou.html', stus=stus, cous=cous)
else:
s_id = request.form.get('student')
c_ids = request.form.getlist('course')
stu = Student.query.get(s_id)
for c_id in c_ids:
cou = Course.query.get(c_id)
cou.students.append(stu)
db.session.add(cou)
db.session.commit()
return '学生选课成功'
>>>html页面解析
{% extends 'base_main.html' %}
{% block title %}
学生课程信息
{% endblock %}
{% block extCSS %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/h3.css') }}">
{% endblock %}
{% block content %}
<form action="" method="post">
<h3>学生1信息:</h3>
<br>
<select name="student" id="">
<option value="">请选择学生信息</option>
{% for stu in stus %}
<option value="{{ stu.s_id }}">{{ stu.s_name }}</option>
{% endfor %}
</select>
<br>
<h3>课程信息:</h3>
<select name="course" id="">
<option value="">请选择课程信息</option>
{% for cou in cous %}
<option value="{{ cou.c_id }}">{{ cou.c_name }}</option>
{% endfor %}
</select>
<br>
<select name="course" id="">
<option value="">请选择课程信息</option>
{% for cou in cous %}
<option value="{{ cou.c_id }}">{{ cou.c_name }}</option>
{% endfor %}
</select>
<br>
<input type="submit" value="提交">
</form>
{% endblock %}
>>>演示结果
>>>比对数据库
实例3:学生查询选课信息
>>>a)视图
# 查询所有学生信息
@stu.route('/allstu/')
def all_stu():
stus = Student.query.all()
return render_template('all_stu.html', stus=stus)
# 查询学生选课信息
@stu.route('/selectcoubystu/<int:id>/')
def select_cou_by_stu(id):
stu = Student.query.get(id)
cous = stu.cou
return render_template('stucourse.html', cous=cous, stu=stu)
>>>b)all_stu.html页面解析
{% extends 'base_main.html' %}
{% block title %}
所有学生信息
{% endblock %}
{% block content %}
<ul>
{% for stu in stus %}
<li>
id:{{ stu.s_id }}
姓名:{{ stu.s_name }}
<a href="/stu/selectcoubystu/{{ stu.s_id }}">所选课程</a>
</li>
{% endfor %}
</ul>
{% endblock %}
>>>c)演示结果:
>>>比对数据库:
实例4:删除学生的某条选课信息
>>>a)视图
@stu.route('/deletecoubyid/<int:s_id>/<int:c_id>/')
def delete_course_by_id(s_id, c_id):
stu = Student.query.get(s_id)
cou = Course.query.get(c_id)
cou.students.remove(stu)
db.session.commit()
return redirect(url_for('stu.all_stu'))
>>>b)stucourse.html页面解析
{% extends 'base_main.html' %}
{% block title %}
学生选课信息
{% endblock %}
{% block content %}
{{ stu.s_name }}选课结果:
<ul>
{% for cou in cous %}
<li>
id:{{ cou.c_id }}
课程:{{ cou.c_name }}
<a href="/stu/deletecoubyid/{{ stu.s_id }}/{{ cou.c_id }}/">删除</a>
</li>
{% endfor %}
</ul>
{% endblock %}
>>>c)演示结果
>>>d)对比数据库
点击id=4的对应的删除,数据库中会删除对应数据,如下图,数据库中s_id=1 c_id=4 的记录已经被删除。
三、数据库的操作
1.创建表create_all()
@stu.route('/createtable/')
def create_db():
db.create_all()
return '创建成功'
2.删除表drop_all()
a)删除db中所有表
@stu.route('/dropalltable/')
def drop_all_table():
db.drop_all()
return '删除成功'
b)删除db中某个表
@stu.route('/droponetable/')
def drop_one_table():
sql = 'delete table student'
db.sesion.execute(sql)
db.session.commit()
return '删除成功'
3.插入 / 创建实例
>>>注意:最后必须要commit才会真正的在数据库中插入数据,否则数据只会保存在缓存区。为了保证事务的一致性,可以用使用try except捕获异常,如果没有执行commit,就回滚上一步操作。
a)模型未初始化
@stu.route('/createstu/')
def create_stu():
stu = Student()
stu.s_name = 'lp%d' % random.randrange(1000)
stu.s_age = '%d' % random.randrange(20)
db.session.add(stu)
try:
db.session.commit()
except:
db.session.rollback()
return '创建学生成功'
b)模型初始化
@stu.route('/createstu/')
def create_stu():
stu = Student(random.randrange(1000), random.randrange(20))
db.session.add(stu)
try:
db.session.commit()
except:
db.session.rollback()
return '创建学生成功'
c)插入多条记录 add_all([ ])
def create_stu():
stu1 = Student(username1, age1)
stu2 = Student(username2, age2)
stu_list = [stu1, stu2]
db.session.add_all(stus)
try:
db.session.commit()
except:
db.session.rollback()
return '创建学生成功'
4.查询
a)查询所有数据
>>>方式1:模型.query.all()
用这种方式查询的结果是一个 list 而不是 queryset
@stu.route('/stulist/')
def stu_all():
stus = Student.query.all()
return render_template('stulist.html', stus=stus)
>>>方式2:原生sql语句 session.execute(sql)
@stu.route('/stulist/')
def stu_all():
sql = 'select * from student;'
stus = db.session.execute(sql)
return render_template('stulist.html', stus=stus)
b)筛选数据
>>>方式1:使用sql语句
@stu.route('/studetail/')
def stu_detail():
sql = 'select * from student where s_name="cy406" '
stus = db.session.execute(sql)
return render_template('stulist.html', stus=stus)
>>>方式2:使用 模型.query.属性
(1)filter(模型.字段.运算符 值)
@stu.route('/studetail/')
def stu_detail():
stus = Student.query.filter(Student.s_name == 'cy253')
return render_template('stulist.html', stus=stus)
运算符:
>>>==等于
实例:查询年龄等于18的学生
stus = Student.query.filter(Student.s_age == 18)
>>>__gt__大于
实例:查询年龄大于18的学生
stus = Student.query.filter(Student.s_age.__gt__(18))
>>>__lt__小于
实例:查询年龄小于18的学生
stus = Student.query.filter(Student.s_age.__lt__(18))
>>>__ge__大于等于
实例:查询年龄大于等于18的学生
stus = Student.query.filter(Student.s_age.__ge__(18))
>>>__le__小于等于
实例:查询年龄小于等于18的学生
stus = Student.query.filter(Student.s_age.__le__(18))
>>>in_([值, 值, 值]) 包含在某些值中
实例:查询年龄在16, 18, 20, 23 中的学生
stus = Student.query.filter(Student.s_age.in_([16, 18, 20, 23]))
(2)filter_by(字段 运算符 值)
stus = Student.query.filter_by(s_name='cy716')
(3)order_by('字段')
order_by默认升序,降序排列在字段前面加减号,如下:order_by('-字段')。
实例:按照年龄降序展示所有学生信息
stus = Student.query.order_by('-s_age')
(4)limit(显示条数)
实例:显示年龄最大的三个学生
stus = Student.query.order_by('-s_age').limit(3)
(5)offset(number) 跳过几条数据
实例:跳过前3条记录,显示2条记录,即显示第4条和第5条记录
stus = Student.query.order_by('-s_age').offset(3).limit(2)
(6)get(值)
flask中,get获取的是一个列表,如果每页获取到内容,get返回一个空列表,get中的参数对应主键字段。
实例:获取id为3的学生
stus = Student.query.get(3)
(7)and_ 并且
实例:查询 id 大于5 且 年龄为18 的学生
stus = Student.query.filter(and_(Student.s_age == 18, Student.s_id>5))
(8)or_ 或
实例:查询年龄大于18 或者 名字为 王小的学生
stus = Student.query.filter(or_(Student.s_age > 18, Student.s_name == '王小'))
(9)not_ 非
not_只能加一个限制条件
实例:查询年龄不是18的学生
stus = Student.query.filter(not_(Student.s_age == 18))
5.删除实例
@stu.route('/deletestu/')
def delete_stu():
stu = Student.query.filter_by(s_id=1).first()
db.session.delete(stu)
db.session.commit()
return redirect(url_for('stu.stu_all'))
6.更新/修改实例
>>>方式1:
@stu.route('/updatestu/')
def update_stu():
stu = Student.query.filter_by(s_id=5).first()
stu.s_name = '王小二'
db.session.commit()
return redirect(url_for('stu.stu_all'))
>>>方式2:update
@stu.route('/updatestu/')
def update_stu():
Student.query.filter(Student.s_id == '1').update({'s_name': '王大锤'})
db.session.commit()
return redirect(url_for('stu.stu_all'))