Flask – 模型的使用

Flask模型

Flask默认并没有提供任何数据库操作的API

我们可以选择任何适合自己项目的数据库来使用

Flask中可以自己的选择数据,用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine)

SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的低层功能。

ORM:

1
2
3
4
5
6
将对对象的操作转换为原生SQL
优点
易用性,可以有效减少重复SQL
性能损耗少
设计灵活,可以轻松实现复杂查询
移植性好

针对于Flask的支持,官网地址

1
pip install flask-sqlalchemy

安装驱动

1
pip install pymysql

定义模型

使用SQLALchemy的对象去创建字段

其中__tablename__指定创建的数据库的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建models.py文件,其中定义模型

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class Student(db.Model):
__tablename__ = "student"

s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
s_name = db.Column(db.String(16), unique=True)
s_age = db.Column(db.Integer, default=1)

其中:

Integer表示创建的s_id字段的类型为整形,

primary_key表示是否为主键

String表示该字段为字符串

unique表示该字段唯一

default表示默认值

autoincrement表示是否自增

创建数据表

在视图函数中我们引入models.py中定义的db

1
2
3
4
5
6
7
8
9
10
11
from App.models import db

@blue.route("/createdb/")
def create_db():
db.create_all()
return "创建成功"

@blue.route('/dropdb/')
def drop_db():
db.drop_all()
return '删除成功'

其中: db.create_all()表示创建定义模型中对应到数据库中的表

db.drop_all()表示删除数据库中的所有的表

初始化SQLALchemy

在定义的__init__.py文件中使用SQLALchemy去整合一个或多个Flask的应用

有两种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 第一种:
from flask_sqlalchemy import SQLALchemy

app = Flask(__name__)
db = SQLAlchemy(app)

# 第二种:
from App.models import db

def create_app():
app = Flask(__name__)
db.init_app(app)
return app

配置数据库的访问地址

官网配置参数

数据库连接的格式:

1
2
3
dialect+driver://username:password@host:port/database
# dialect数据库实现
# driver数据库的驱动

例子: 访问mysql数据库,驱动为pymysql,用户为root,密码为123456,数据库的地址为本地,端口为3306,数据库名称HelloFlask

设置如下: mysql+pymysql://root:123456@localhost:3306/HelloFlask

在初始化__init__.py文件中如下配置:

1
2
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@localhost:3306/HelloFlask"

CRUD操作

语法:

1
类名.query.xxx

获取查询集:

1
2
3
all()
filter(类名.属性名==xxx)
filter_by(属性名=xxx)

数据操作:

1
2
3
4
5
6
7
8
9
10
11
# 在事务中处理,数据插入

db.session.add(object)

db.session.add_all(list[object])

db.session.delete(object)

db.session.commit()

# 修改和删除基于查询

向学生表中添加数据

1
2
3
4
5
6
7
8
9
10
@blue.route('/createstu/')
def create_stu():
s = Student()
s.s_name = '小花%d' % random.randrange(100)
s.s_age = '%d' % random.randrange(30)

db.session.add(s)
db.session.commit()

return '添加成功'

提交事务,使用commit提交我们的添加数据的操作

批量增加

第一种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@blue.route('/createstus/')
def create_users():
stus = []
for i in range(5):
# 实例化Student的对象
s = Student()
# 对象的属性赋值
s.s_name = '张三%s' % random.randrange(10000)
s.s_age = '%d' % random.randrange(100)
stus.append(s)
# 添加需要创建的数据
db.session.add_all(stus)
# 提交事务到数据库
db.session.commit()

return '创建成功'

注:在创建单条数据的时候使用db.session.add(),在创建多条数据的时候使用db.session.add_all()

第二种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
@blue.route('/createstus/')
def create_users():
stus = []
for i in range(5):
# 使用类的初始化去创建Student对象
s = Student('张三%s' % random.randrange(10000),
'%d' % random.randrange(100))
stus.append(s)

db.session.add_all(stus)
db.session.commit()

return '创建成功'

获取所有学生信息

将学生的全部信息获取到,并且返回给页面,在页面中使用for循环去解析即可

1
2
3
4
@blue.route("/getstudents/")
def get_students():
students = Student.query.all()
return render_template("StudentList.html", students=students)

获取s_id=1的学生的信息

写法1:

1
students = Student.query.filter(Student.s_id == 1)

写法2:

1
students = Student.query.filter_by(s_id=1)

注意:filter中可以接多个过滤条件

写法3:

1
2
sql = 'select * from student where s_id=1'
students = db.session.execute(sql)

修改学生的信息

写法1:

1
2
3
students = Student.query.filter_by(s_id=3).first()
students.s_name = '哈哈'
db.session.commit()

写法2:

1
2
Student.query.filter_by(s_id=3).update({'s_name':'娃哈哈'})
db.session.commit()

删除一个学生的信息

写法1:

1
2
3
students = Student.query.filter_by(s_id=2).first()
db.session.delete(students)
db.session.commit()

写法2:

1
2
3
students = Student.query.filter_by(s_id=1).all()
db.session.delete(students[0])
db.session.commit()

注意:filter_by后的结果是一个list的结果集

重点注意:在增删改中如果不commit的话,数据库中的数据并不会更新,只会修改本地缓存中的数据,所以一定需要db.session.commit()

查询操作深入

使用运算符

获取查询集

1
2
3
filter(类名.属性名.运算符(‘xxx’))

filter(类名.属性 数学运算符 值)

运算符:

1
2
3
4
5
6
7
8
9
contains: 包含
startswith:以什么开始
endswith:以什么结束
in_:在范围内
like:模糊
__gt__: 大于
__ge__:大于等于
__lt__:小于
__le__:小于等于

筛选:

1
2
3
4
5
6
offset()
limit()
order_by()
get()
first()
paginate()

逻辑运算:

1
2
3
4
5
6
7
8
9
10
11

and_
filter(and_(条件),条件…)


or_
filter(or_(条件),条件…)


not_
filter(not_(条件),条件…)

例子1:

  1. 查询学生的id为3,4,5,6,16的的学生信息,使用in_逻辑运算

    1
    2
    3
    4
    @blue.route('/getstubyids/')
    def get_stu_by_ids():
    students = Student.query.filter(Student.s_id.in_([3,4,5,6,16]))
    return render_template('StudentList.html', students=students)
  2. 查询学生的年龄小于18岁的学生的信息

    1
    Student.query.filter(Student.s_age < 18)
  3. 查询学生的年龄小于18岁的学生的信息,lt小于

    1
    students = Student.query.filter(Student.s_age.__lt__(15))
  4. 查询学生的年龄小于等于18岁的学生的信息,le小于等于

    1
    students = Student.query.filter(Student.s_age.__le__(15))
  5. 查询学生的姓名以什么开始或者以什么结尾的学生的信息startswith和endswith

    1
    2
    students = Student.query.filter(Student.s_name.startswith('张'))
    students = Student.query.filter(Student.s_name.endswith('2'))
  6. 查询id=4的学生的信息

    1
    2
    Student.query.get(4)
    # 获取的结果是学生的对象
  7. 模糊搜索like

    1
    2
    3
    4
    # %:代表一个或者多个
    # _:代表一个

    Student.query.filter(Student.s_name.like('%张%'))
  8. 分页,查询第二页的数据4条

    1
    2
    # 第一个参数是那一页,第二个参数是一页的条数,第三个参数是是否输出错误信息
    students = Student.query.paginate(2, 4, False).items

例子2:

跳过offset几个信息,截取limit结果的几个值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 按照id降序排列
stus = Student.query.order_by('-s_id')

# 按照id降序获取三个
stus = Student.query.order_by('-s_id').limit(3)

# 获取年龄最大的一个
stus = Student.query.order_by('-s_age').first()

# 跳过3个数据,查询5个信息
stus = Student.query.order_by('-s_age').offset(3).limit(5)

# 跳过3个数据
stus = Student.query.order_by('-s_age').offset(3)

# 获取id等于24的学生
stus = Student.query.filter(Student.s_id==24)
stus = Student.query.get(24)

例子3:

查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
from sqlalchemy import and, or, not_

# 查询多个条件
stus = Student.query.filter(Student.s_age==18, Student.s_name=='雅典娜')

# and_ 并且条件
stus = Student.query.filter(and_(Student.s_age==18, Student.s_name=='雅典娜'))

# or_ 或者条件
stus = Student.query.filter(or_(Student.s_age==18, Student.s_name=='火神'))

# not_ 非
stus = Student.query.filter(not_(Student.s_age==18), Student.s_name=='火神')

分页:

flask_sqlalchemy_paginate
flask_sqlalchemy_paginate

后端数据处理:

1
2
3
4
5
6
7
8
9
10
# 查询第几页的数据	
page = int(request.args.get('page', 1))

# 每一页的条数多少,默认为10条
per_page = int(request.args.get('per_page', 10))

# 查询当前第几个的多少条数据
paginate = Student.query.order_by('-s_id').paginate(page, per_page, error_out=False)

stus = paginate.items

前端数据展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<h2>学生信息</h2>
{% for stu in stus %}
id:{{ stu.s_id }}
姓名:{{ stu.s_name }}
年龄:{{ stu.s_age }}
<br>
{% endfor %}
<br>
总页数: {{ paginate.pages }}
<br>
一共{{ paginate.total }}条数据
<br>
当前页数:{{ paginate.page }}
<br>
{% if paginate.has_prev %}
<a href="/stupage/?page={{ paginate.prev_num }}">上一页</a>:{{ paginate.prev_num }}
{% endif %}

{% if paginate.has_next %}
<a href="/stupage/?page={{ paginate.next_num }}">下一页</a>:{{ paginate.next_num }}
{% endif %}
<br>

<br>
页码:{% for i in paginate.iter_pages() %}
<a href="/stupage/?page={{ i }}">{{ i }}</a>
{% endfor %}