Flask中sqlachemy的使用
SQLAlchemy
一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作,flask-sqlalchemy
是一个简化了SQLAlchemy操作的flask扩展。
SQLAlchemy在flask中的应用
(1)安装依赖包
在Flask中使用mysql数据库,需要安装一个flask-sqlalchemy
的扩展
pip install flask-sqlalchemy
要连接mysql数据库,仍需要安装数据库驱动
pip install MySQL-Python
如果报错:信息如下
Collecting mysql-python
Downloading https://files.pythonhosted.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip (108kB)
100% |████████████████████████████████| 112kB 148kB/s
Complete output from command python setup.py egg_info:
sh: mysql_config: command not found
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/tmp/pip-build-WXInHg/mysql-python/setup.py", line 17, in <module>
metadata, options = get_config()
File "setup_posix.py", line 43, in get_config
libs = mysql_config("libs_r")
File "setup_posix.py", line 25, in mysql_config
raise EnvironmentError("%s not found" % (mysql_config.path,))
EnvironmentError: mysql_config not found
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-WXInHg/mysql-python/
You are using pip version 8.1.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
需要安装:python-mysqldb
sudo apt-get install python-mysqldb
然后再安装MySQL-Python
(flask) [email protected]-virtual-machine:~/flask-tutorial$ sudo pip install mysql-python
The directory '/home/ubantu/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/ubantu/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting mysql-python
Downloading https://files.pythonhosted.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip (108kB)
100% |████████████████████████████████| 112kB 24kB/s
Installing collected packages: mysql-python
Running setup.py install for mysql-python ... done
Successfully installed mysql-python-1.2.5
You are using pip version 8.1.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
mysql数据库驱动
python3
中使用pymysql
作为数据库驱动
import pymysql
pymysql.install_sa_mysqldb()
python2
中使用MySQL-Python
作为数据库驱动
(2)配置连接信息
- 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://用户名:密码@127.0.0.1:3306/库名'
- 设置每次请求结束后会自动提交数据库中的改动(官方
建议不要使用
)
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
- 修改表中数据时,同步修改模型类(
建议使用
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
- 查询时会显示原始SQL语句
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
- 创建连接对象
db = SQLAlchemy(app)
(3)常用的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字符串,对较长或不限长度的字符串做了优化 |
Boolen | bool:布尔值 |
Date | datetime.date:时间 |
Time | datetime.datetime:日期和时间 |
LargeBinary | str:二进制文件 |
(4)常用SQLAlchemy列选项
选项名 | 说明 |
---|---|
primary_key | 如果为True,代表主键 |
unique | 如果为True,代表这列不允许出现重复值 |
index | 如果为True,为这列创建索引,提高查询效率 |
nullable | 如果为True,允许有空值,如果未False,不允许有空值 |
default | 为该列定义默认值 |
(5)常用的SQLAlchemy关系选项
选项名 | 说明 |
---|---|
backref | 在关系的另一模型中添加反向引用 |
primary join | 明确指定两个模型之间使用的连结条件 |
uselist | 如果为False,不使用列表,而是使用标量值 |
order_by | 指定关系中记录的排序方式 |
secondary | 指定多对多中记录的排序方式 |
secondary join | 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件 |
(6)创建数据表:
# coding:utf-8
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# create database db_flask default charset utf8 collate utf8_general_ci;
class Config(object):
"""配置参数"""
SQLALCHEMY_DATABASE_URL = "myslq://root:[email protected]:3306/db_flask"
# 设置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)
# 需要手动添加,方便使用Role.user查询用户对象,user列不是真实存在的,backref="role"为了方便通过User.role获取角色对象,
# 因为使用User.role_id只能获取到角色id,要想获取角色对象,还需要再在Role表中查询一次
users = db.relationship("User", backref="role")
def __repr__(self):
"""定义之后,可以让显示对象的时候更直观,类似于Django中的__str__"""
return "Rloe object: name=%s" % self.name
# In [4]: Role.query.get(1)
# Out[4]: Rloe object: name=admin
# In [5]:
# In [49]: ro = Role.query.get(1)
# In [50]: ro.users
# Out[50]: [<User 2>, <User 4>]
# In [51]:
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), nullable=False) # nullable=False 参数必须传
role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))
# In [53]: usr = User.query.get(1)
# 此处的role是来自于Role表中users字段中定义的backref属性值
# In [54]: usr.role
# Out[54]: <Role 2>
# In [55]: usr.role.name
# Out[55]: u'stuff'
# In [56]:
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()
usr1 = User(name='zhao', email='[email protected]', password='123456', role_id=role2.id)
usr2 = User(name='qian', email='[email protected]', password='123456', role_id=role1.id)
usr3 = User(name='sui', email='[email protected]', password='123456', role_id=role2.id)
usr4 = User(name='li', email='[email protected]', password='123456', role_id=role1.id)
# 一次保存多条数据
db.session.add_all([usr1, usr2, usr3, usr4])
db.session.commit()
运行程序,创建数据表:
(flask) [email protected]-virtual-machine:~/flask-tutorial$ python db_demo.py
(7)常用的SQLAlchemy查询执行器
方法 | 说明 |
---|---|
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如果未查询到,返回None |
first_or_404 | 返回查询的第一个结果,如果未查询到,返回404 |
get() | 返回指定主键对应的行,如不存在,返回None |
get_or_404 | 返回指定主键对应的行,如不存在,返回404 |
count | 返回查询的结果的数量 |
paginate | 返回一个Paginate对象,它包含指定范围内的结果 |
(8)查询数据表
- 查询多条数据:
query.all()
:
In [1]: from db_demo import *
In [2]: Role.query.all()
Out[2]: [<Role 1>, <Role 2>]
In [3]: lst = Role.query.all()
In [4]: r = lst[0]
In [5]: type(r)
Out[5]: db_demo.Role
In [6]: r.name
Out[6]: u'admin'
In [7]:
- 查询一条数据:
query.first()
: -
query.get
,只能接受主键字段作为查询条件
In [7]: Role.query.first()
Out[7]: <Role 1>
In [8]: r = Role.query.first()
In [9]: r.name
Out[9]: u'admin'
In [10]:
In [11]: r = Role.query.get(2)
In [12]: r
Out[12]: <Role 2>
In [13]: r.name
Out[13]: u'stuff'
In [14]:
- SQLAlchemy原装查询方式
In [14]: db.session.query(Role).all()
Out[14]: [<Role 1>, <Role 2>]
In [15]: db.session.query(Role).get(2)
Out[15]: <Role 2>
In [16]: db.session.query(Role).first()
Out[16]: <Role 1>
In [17]:
(9)常用的SQLAlchemy查询过滤器
过滤器 | 说明 |
---|---|
filter | 把过滤器添加到原查询上,返回一个新查询结果 |
filter_by() | 把等值过滤器添加到原查询上,返回一个新查询 |
limit | 使用指定的值限定原查询返回的结果 |
offset () | 偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对查询结果进行排序,返回一个新查询 |
group_by() | 根据指定条件对查询结果进行分组,返回一个新查询 |
filter_by()
In [17]: User.query.filter_by(name='zhao')
Out[17]: <flask_sqlalchemy.BaseQuery at 0x7f06d4f3ae50>
In [18]: User.query.filter_by(name='zhao').all()
Out[18]: [<User 1>]
In [19]: User.query.filter_by(name='zhao').first()
Out[19]: <User 1>
In [20]: user = User.query.filter_by(name='zhao').first()
In [21]: user.name
Out[21]: u'zhao'
In [22]: user.email
Out[22]: u'[email protected]'
In [23]:
filter()
In [27]: user = User.query.filter(User.name=='zhao', User.role_id==2).first()
In [28]: user.name
Out[28]: u'zhao'
In [29]:
- 或查寻
_or
In [29]: from sqlalchemy import or_
In [30]: user = User.query.filter(or_(User.name=='zhao', User.email.startswith('li'))).all()
In [31]: user
Out[31]: [<User 1>, <User 4>]
In [32]: user[0].name
Out[32]: u'zhao'
In [33]:
- 完整查询
User.query.filter().offset().limit().order_by().all()
- 跳过前两条数据
offset(2)
In [35]: lst = User.query.offset(2).all()
In [36]: lst[0].name
Out[36]: u'sui'
In [37]: lst[1].name
Out[37]: u'li'
In [38]: lst
Out[38]: [<User 3>, <User 4>]
In [39]:
- 取两条数据
limit(2)
In [39]: lst = User.query.offset(1).limit(2).all()
In [40]: lst
Out[40]: [<User 2>, <User 3>]
In [41]: lst[0].name
Out[41]: u'qian'
In [42]: lst[1].name
Out[42]: u'sui'
In [43]:
- 排序
order_by()
In [43]: lst = User.query.order_by(User.id.desc()).all()
In [44]: lst
Out[44]: [<User 4>, <User 3>, <User 2>, <User 1>]
In [45]:
- 分组
group_by()
In [46]: from sqlalchemy import func
In [47]: db.session.query(User.role_id, func.count(role_id)).group_by(User.role_id).all()
In [48]: db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id).all()
Out[48]: [(1L, 2L), (2L, 2L)]
In [49]:
(10)修改数据
In [8]: usr = User.query.get(1)
In [9]: usr.name
Out[9]: u'zhao'
In [10]: usr.name = "jin"
In [11]: db.session.add(usr)
In [12]: db.session.commit()
In [13]: User.query.filter_by(name="qian").update({"name":"yin", "email":"[email protected]"})
Out[13]: 1L
In [14]: db.session.commit()
In [15]:
(11)删除数据
In [16]: user = User.query.get(3)
In [17]: db.session.delete(user)
In [18]: db.session.commit()
In [19]: