Flask后端笔记
数据库的设置
Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在表中,表用来给应用的实体建模,表的列数是固定的,行数是可变的。它使用结构化的查询语言。关系型数据库的列定义了表中表示的实体的数据属性。比如:商品表里有name、price、number等。 Flask本身不限定数据库的选择,你可以选择SQL或NOSQL的任何一种。也可以选择更方便的SQLALchemy,类似于Django的ORM。SQLALchemy实际上是对数据库的抽象,让开发者不用直接和SQL语句打交道,而是通过Python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升。
SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。
数据库安装
安装服务端
sudo apt-get install mysql-server
安装客户端
sudo apt-get install mysql-client
sudo apt-get install libmysqlclient-dev
数据库的基本命令
登录数据库
mysql -u root -p
创建数据库,并设定编码
create database <数据库名> charset=utf8;
显示所有数据库
show databases;
在Flask中使用mysql数据库
需要安装一个flask-sqlalchemy的扩展。
pip install flask-sqlalchemy
要连接mysql数据库,仍需要安装flask-mysqldb
pip install flask-mysqldb
或者
pip install MySQL-Python
(Python2优先安装)
使用Flask-SQLAlchemy管理数据库
使用Flask-SQLAlchemy扩展操作数据库,首先需要建立数据库连接。数据库连接通过URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中。
对比下Django和Flask中的数据库设置:
Django的数据库设置:
Flask的数据库设置:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test3'
常用的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 | 二进制文件 |
常用的SQLAlchemy列选项
选项名 | 说明 |
---|---|
primary_key | 如果为True,代表表的主键 |
unique | 如果为True,代表这列不允许出现重复的值 |
index | 如果为True,为这列创建索引,提高查询效率 |
nullable | 如果为True,允许有空值,如果为False,不允许有空值 |
default | 为这列定义默认值 |
常用的SQLAlchemy关系选项
选项名 | 说明 |
---|---|
backref | 在关系的另一模型中添加反向引用 |
primary join | 明确指定两个模型之间使用的联结条件 |
uselist | 如果为False,不使用列表,而使用标量值 |
order_by | 指定关系中记录的排序方式 |
secondary | 指定多对多中记录的排序方式 |
secondary join | 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件 |
demo.py
# coding:utf-8
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
class Config(object):
"""配置参数"""
# sqlalchemy的配置参数
SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/db_python04"
# 设置sqlalchemy自动更跟踪数据库
SQLALCHEMY_TRACK_MODIFICATIONS = True
app.config.from_object(Config)
# 创建数据库sqlalchemy工具对象
db = SQLAlchemy(app)
class Role(db.Model):
"""用户角色/身份表"""
__tablename__ = "tbl_roles"
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), unique=True)
users = db.relationship("User", backref="role")
#repr()方法显示一个可读字符串
def __repr__(self):
"""定义之后,可以让显示对象的时候更直观"""
return "Role object: name=%s" % self.name
# 表名的常见规范
# ihome -> ih_user 数据库名缩写_表名
# tbl_user tbl_表名
# 创建数据库模型类
class User(db.Model):
"""用户表"""
__tablename__ = "tbl_users" # 指明数据库的表名
id = db.Column(db.Integer, primary_key=True) # 整型的主键,会默认设置为自增主键
name = db.Column(db.String(64), unique=True)
email = db.Column(db.String(128), unique=True)
password = db.Column(db.String(128))
role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))
def __repr__(self):
return "User object: name=%s" % self.name
if __name__ == '__main__':
# 清除数据库里的所有数据
db.drop_all()
# 创建所有的表
db.create_all()
# 创建对象
role1 = Role(name="admin")
# session记录对象任务
db.session.add(role1)
# 提交任务到数据库中
db.session.commit()
role2 = Role(name="stuff")
db.session.add(role2)
db.session.commit()
us1 = User(name='wang', email='wang@163.com', password='123456', role_id=role1.id)
us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=role2.id)
us3 = User(name='chen', email='chen@126.com', password='987654', role_id=role2.id)
us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=role1.id)
# 一次保存多条数据
db.session.add_all([us1, us2, us3, us4])
db.session.commit()
查询操作
# 查询所有
Role.query.all()
Out[2]: [<db_demo.Role at 0x10388d190>, <db_demo.Role at 0x10388d310>]
In [3]: li = Role.query.all()
In [4]: li
Out[4]: [<db_demo.Role at 0x10388d190>, <db_demo.Role at 0x10388d310>]
In [5]: r = li[0]
In [6]: type(r)
Out[6]: db_demo.Role
In [7]: r.name
Out[7]: u'admin'
# 查询第一条
In [8]: Role.query.first()
Out[8]: <db_demo.Role at 0x10388d190>
In [9]: r = Role.query.first()
In [10]: r.name
Out[10]: u'admin'
# 根据主键id获取对象
In [11]: r = Role.query.get(2)
In [12]: r
Out[12]: <db_demo.Role at 0x10388d310>
In [13]: r.name
Out[13]: u'stuff'
# 另一种查询方式
In [15]: db.session.query(Role).all()
Out[15]: [<db_demo.Role at 0x10388d190>, <db_demo.Role at 0x10388d310>]
In [16]: db.session.query(Role).get(2)
Out[16]: <db_demo.Role at 0x10388d310>
In [17]: db.session.query(Role).first()
Out[17]: <db_demo.Role at 0x10388d190>
常用的SQLAlchemy查询过滤器
过滤器 | 说明 |
---|---|
filter() | 把过滤器添加到原查询上,返回一个新查询 |
filter_by() | 把等值过滤器添加到原查询上,返回一个新查询 |
limit | 使用指定的值限定原查询返回的结果 |
offset() | 偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对原查询结果进行排序,返回一个新查询 |
group_by() | 根据指定条件对原查询结果进行分组,返回一个新查询 |
常用的SQLAlchemy查询执行器
方法 | 说明 |
---|---|
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如果未查到,返回None |
first_or_404() | 返回查询的第一个结果,如果未查到,返回404 |
get() | 返回指定主键对应的行,如不存在,返回None |
get_or_404() | 返回指定主键对应的行,如不存在,返回404 |
count() | 返回查询结果的数量 |
paginate() | 返回一个Paginate对象,它包含指定范围内的结果 |
查询:过滤器
In [18]: User.query.filter_by(name="wang")
Out[18]: <flask_sqlalchemy.BaseQuery at 0x1038c90d0>
In [19]: User.query.filter_by(name="wang").all()
Out[19]: [<db_demo.User at 0x1038c87d0>]
In [20]: User.query.filter_by(name="wang").first()
Out[20]: <db_demo.User at 0x1038c87d0>
In [21]: user = User.query.filter_by(name="wang").first()
In [22]: user.name
Out[22]: u'wang'
In [23]: user.email
Out[23]: u'wang@163.com'
In [24]: User.query.filter_by(name="wang", role_id=1).first()
Out[24]: <db_demo.User at 0x1038c87d0>
In [25]: User.query.filter_by(name="wang", role_id=2).first()
In [26]: user = User.query.filter_by(name="wang", role_id=2).first()
In [27]: type(user)
Out[27]: NoneType
In [28]: user = User.query.filter(User.name=="wang", User.role_id==1).first()
In [29]: user
Out[29]: <db_demo.User at 0x1038c87d0>
In [30]: user.name
Out[30]: u'wang'
逻辑非,返回名字不等于wang的所有数据。
User.query.filter(User.name!='wang').all()
逻辑与,需要导入and,返回and()条件满足的所有数据。
from sqlalchemy import and_
User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()
逻辑或,需要导入or_
from sqlalchemy import or_
User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()
not_ 相当于取反
from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()
偏移
# offset偏移 跳过几条
In [36]: User.query.offset(2).all()
Out[36]: [<db_demo.User at 0x1038c0950>, <db_demo.User at 0x1038ef310>]
In [37]: li = User.query.offset(2).all()
In [38]: li[0].name
Out[38]: u'chen'
In [39]: li[1].name
Out[39]: u'zhou'
In [42]: li = User.query.offset(1).limit(2).all()
In [43]: li
Out[43]: [<db_demo.User at 0x1038fd990>, <db_demo.User at 0x1038c0950>]
In [44]: li[0].name
Out[44]: u'zhang'
In [45]: li[1].name
Out[45]: u'chen'
排序
In [50]: User.query.order_by("-id").all()
Out[50]:
[<db_demo.User at 0x1038ef310>,
<db_demo.User at 0x1038c0950>,
<db_demo.User at 0x1038fd990>,
<db_demo.User at 0x1038c87d0>]
In [51]:
In [51]: li = User.query.order_by(User.id.desc()).all()
In [52]: li
Out[52]:
[<db_demo.User at 0x1038ef310>,
<db_demo.User at 0x1038c0950>,
<db_demo.User at 0x1038fd990>,
<db_demo.User at 0x1038c87d0>]
In [53]: li[0].name
Out[53]: u'zhou'
In [54]: li[3].name
Out[54]: u'wang'
分组
In [55]: from sqlalchemy import func
In [56]: db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id)
Out[56]: <flask_sqlalchemy.BaseQuery at 0x103a38050>
In [57]: db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id).all()
Out[57]: [(1L, 2L), (2L, 2L)]
从角色查询用户和从用户查询角色
In [61]: ro = Role.query.get(1)
In [62]: type(ro)
Out[62]: db_demo.Role
In [63]: ro.users
Out[63]: [<db_demo.User at 0x1038c87d0>, <db_demo.User at 0x1038ef310>]
In [64]: ro.users[0].name
Out[64]: u'wang'
In [65]: ro.users[1].name
Out[65]: u'zhou'
In [67]: user
Out[67]: <db_demo.User at 0x1038c87d0>
In [68]: user.role_id
Out[68]: 1L
In [69]: Role.query.get(user.role_id)
Out[69]: <db_demo.Role at 0x10388d190>
In [70]: user.role
Out[70]: <db_demo.Role at 0x10388d190>
In [71]: user.role.name
Out[71]: u'admin'
优化查询显示
更新
# 更新
In [14]: User.query.filter_by(name="zhou").update({"name": "python", "email": "python@itast.cn"})
Out[14]: 1L
In [15]: db.session.commit()
In [16]:
删除
# 删除
In [16]: user = User.query.get(3)
In [17]: db.session.delete(user)
In [18]: db.session.commit()
In [19]:
先查询后更新或删除