每个项目都离不开数据库,所以要是打算用Flask写一个程序,我这边选择了flask-sqlalchemy
Flask-SQLAlchemy 采用数据库抽象层来操作数据库,也称为对象关系映射(Object-Relational Mapper, ORM),在用户不知不觉的情况下把高层的面向对象操作转换成低层的数据库指令,
1、下载包
pip install flask-sqlalchemy
(其实上章已经添加过了)
2、在 app/__init__.py 中实例化了 SQLAlchemy 类:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from flask import Flask
app = Flask(__name__)
from app.controller import test
#######以下是改动部分#####
from flask_sqlalchemy import SQLAlchemy
# 配置数据库的连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@localhost:3306/flask'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
#让app 能找到sql.py文件
from app.controller import sql
3、定义模型
模型类可以理解为数据库中的一张表,Flask-SQLAlchemy 提供了一个基类和一系列辅助类和函数来让我们定义模型的结构。我们直接在 app 文件夹下创建一个 models.py 文件。
我这边只举个简单的例子,建一个user表
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 当前项目相关的模型文件 所有 实体类
from app import db
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
name = db.Column(db.String(16), nullable=False, unique=True)
password = db.Column(db.String(16), nullable=False, unique=False)
hobby = db.Column(db.String(255), nullable=False, unique=False)
# __repr__()用于显示给开发人员。
def __repr__(self):
# return '<User %r>' % self.name
return 'User(id: %d, name: %s, password: %s, hobby: %s)' % (self.id, self.name, self.password, self.hobby)
# 将db.Model 转化成json(特定方法)
def to_json(self):
dict = self.__dict__
if "_sa_instance_state" in dict:
del dict["_sa_instance_state"]
return dict
注意:
__repr__() 方法返回一个具有可读性的字符串表示模型,可以在调试和测试时使用。
常用列选项
primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值,如default=1
常用的关系选项
backref 在关系的另一模型中添加反向引用,用于找到父表
primary join 明确指定两个模型之间使用的联结条件
uselist 如果为False,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定多对多中记录的排序方式
secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
db.Model 对象to json的方法比较特殊!
4、python命令行实现对数据库的操作
创建启动脚本 manage.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from app import app, db
from flask_script import Manager, Shell
from flask_migrate import Migrate, MigrateCommand
manager = Manager(app)
migrate = Migrate(app, db)
def make_shell_context():
return dict(app=app, db=db)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
这个脚本首先创建程序,然后增加了两个命令:shell 和 db,我们之后可以在命令行中直接使用。
下面我们就在命令行中操作一下数据库。
先打开cmd,然后切换到当前项目目录下
然后激活本项目的环境
首先执行:
python manage.py runserver
打开浏览器:
表面该启动脚本启动项目成功
在当前的命令行接着执行:
//创建 migrations 文件夹及相关文件
python manage.py db init
删除该目录,然后再执行一次
然后执行 :
//自动创建迁移脚本
python manage.py db migrate
//创建数据表或者升级到最新版本
python manage.py db upgrade
报错:ImportError: No module named 'MySQLdb'
参考:https://stackoverflow.com/questions/454854/no-module-named-mysqldb
执行命令:
pip install mysqlclient
又报错: error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
参考:https://github.com/benfred/implicit/issues/76
失败!!!
那就换种方法:
通过使用Christoph Gohlke收集的
非扩展Windows二进制文件Python扩展包来解决这个障碍。下载相应的mysqlclient轮(* .whl)文件。对于Python 3.7,单击“mysqlclient-1.3.13-cp37-cp37m-win_amd64.whl”,它将下载到您的计算机。然后通过以下方式手动安装包pip
:
再次运行命令:
成功~
以后模型类有改动,比如删除或添加列,都要执行这两个命令,更新数据库表。现在在项目目录下应该自动生成了名为 dev 的数据库。
接下来执行如下命令进入 Python Shell:
python manage.py shell
创建表
使用 db.create_all() 就可以根据模型类创建表。如图:
使用 db.drop_all() 方法就可以删除所有的表,但是这种方式比较粗暴,所有的数据也一同销毁了。
查询表:
由于数据库是空的,所以就返回了这个
命令行就介绍到这了,接下来通过python代码来实现对数据库的操作
5、python代码来实现对数据库的操作
它所需的环境跟命令行一样
sql.py:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from flask import jsonify, request
from app import app
from app.models import db, User
@app.route("/createAll", methods=['GET', ])
def createAllTables():
db.create_all()
return jsonify(msg="create successfully!")
# 插入记录、更新数据
@app.route("/add", methods=['POST', ])
def addTables():
name = request.form.get("name", None)
password = request.form.get("password", None)
hobby = request.form.get("hobby", None)
obj = User(name=name, password=password, hobby=hobby)
db.session.add(obj)
db.session.commit()
return jsonify(msg="add successfully!")
# 查询
@app.route("/selectAll", methods=['GET', ])
def selectAll():
users = User.query.all()
print(users)
array_list = []
for user in users:
array_list.append(user.to_json())
return jsonify(msg=array_list)
# 删除
@app.route("/delete", methods=['GET', ])
def delete():
user = User.query.filter_by(name='aaa').first()
if user is not None:
db.session.delete(user)
db.session.commit()
return jsonify(msg='success')
else:
return jsonify(msg='error')
注意:
“query”接口拥有丰富的方法,这里列举一些常用的:
1、“filter_by()”方法,对查询结果过滤,参数必须是键值对”key=value”
users = User.query.filter_by(name='aaa')
# WHERE name='aaa' AND hobby='wu'
users = User.query.filter_by(name='aaa', hobby='wu')
2、“filter()”,对查询结果过滤,比”filter_by()”方法更强大,参数是布尔表达式
# WHERE age<20
users = User.query.filter(User.age<20)
# WHERE name LIKE 'J%' AND age<20
users = User.query.filter(User.name.startswith('J'), User.age<20)
多个查询条件用逗号分割。
3、“first()”,取返回列表中的第一个元素,当我们只查询一条记录时非常有用
user = User.query.filter_by(name='aaa').first()
4、“order_by()”,排序
from sqlalchemy import desc
# ORDER BY name
user = User.query.order_by(User.name)
# ORDER BY age DESC, name
user = User.query.order_by(desc(User.age), User.name)
5、“limit()”和”offset()”,分页
# LIMIT 10 OFFSET 10
user = User.query.limit(10).offset(10)
6、“slice(start, stop)”,分页
# LIMIT 2 OFFSET 1
user = User.query.slice(1, 3)
从start位置开始取记录,到stop位置前结束。本质上来说,SQLAlchemy会将其翻译成LIMIT/OFFSET语句来实现,上例中的”slice(1, 3)”等同于”LIMIT 2 OFFSET 1″。
6、测试:
1、测试数据插入/数据更新
2、测试查询数据
3、测试删除
7、补充
用Binds操作多个数据库:
先修改 app/__init__.py,增加以下
SQLALCHEMY_BINDS={
'users':'mysql://localhost/usersdb',
'db01': 'mysql://...',
'db02': 'mysql://...',
'db03': 'mysql://...'
}
app.config['SQLALCHEMY_BINDS'] = SQLALCHEMY_BINDS
然后再修改models.py:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 当前项目相关的模型文件 所有 实体类
from app import db
class Teacher(db.Model):
__bind_key__ = 'users'
__tablename__ = "user"
id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
name = db.Column(db.String(16), nullable=False, unique=True)
password = db.Column(db.String(16), nullable=False, unique=False)
hobby = db.Column(db.String(255), nullable=False, unique=False)
当我们声明模型时,使用__bind_key__属性指定bind,用来绑定指定的数据库。
在SQLAlchemy中,一个binds是可以执行SQL语句,且通常是一个连接或引擎的东西。在Flask-SQLAlchemy中,bind总是背后自动为你创建好引擎。每一个引擎中都会关联一个键(bind key)。这个键会在模型声明时使用来把一个模型关联到一个特定引擎。如果没有为模型指定bind key,会默认连接(即SQLALCHEMY_DATABASE_URI配置的值)
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 二进制文件
Enum enum 枚举类型
具体解释:
1. Integer:整形,映射到数据库中是int,bigint类型。
2. Float:浮点类型,映射到数据库中是float类型。他占据的32位。
3. Double:双精度浮点类型,映射到数据库中是double类型,占据64位。
4. String:可变字符类型,映射到数据库中是varchar类型.
5. Boolean:布尔类型,映射到数据库中的是tinyint类型。
6. DECIMAL:定点类型。是专门为了解决浮点类型精度丢失的问题的。在存储钱相关的字段的时候建议大家都使用这个数据类型。并且这个类型使用的时候需要传递两个参数,第一个参数是用来标记这个字段总能能存储多少个数字,第二个参数表示小数点后有多少位。
7. Enum:枚举类型。指定某个字段只能是枚举中指定的几个值,不能为其他值。在ORM模型中,使用Enum来作为枚举
8. Date:存储时间,只能存储年月日。映射到数据库中是date类型。在Python代码中,可以使用`datetime.date`来指定
9. DateTime:存储时间,可以存储年月日时分秒毫秒等。映射到数据库中也是datetime类型。在Python代码中,可以使用`datetime.datetime`来指定。示例代码如下:
10. Time:存储时间,可以存储时分秒。映射到数据库中也是time类型。在Python代码中,可以使用`datetime.time`来至此那个。
11. Text:存储长字符串。一般可以存储6W多个字符。如果超出了这个范围,可以使用LONGTEXT类型。映射到数据库中就是text类型。
12. LONGTEXT:长文本类型,映射到数据库中是longtext类型。
参考:
https://github.com/pallets/flask-sqlalchemy
http://flask-sqlalchemy.pocoo.org/2.3/
https://www.jianshu.com/p/cc90a14856c5
http://www.bjhee.com/flask-ext4.html