每个项目都离不开数据库,所以要是打算用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,然后切换到当前项目目录下

然后激活本项目的环境

SQLAlchemy 对应python版本 sqlalchemy flask_User


首先执行:

python manage.py runserver

SQLAlchemy 对应python版本 sqlalchemy flask_数据库_02

打开浏览器:

SQLAlchemy 对应python版本 sqlalchemy flask_User_03

表面该启动脚本启动项目成功

 

在当前的命令行接着执行:

//创建 migrations 文件夹及相关文件
python manage.py db init

SQLAlchemy 对应python版本 sqlalchemy flask_python_04

删除该目录,然后再执行一次

SQLAlchemy 对应python版本 sqlalchemy flask_User_05

然后执行 :

//自动创建迁移脚本
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

下载:https://visualstudio.microsoft.com/zh-hans/downloads/?rr=https%3A%2F%2Fgithub.com%2Fbenfred%2Fimplicit%2Fissues%2F76

SQLAlchemy 对应python版本 sqlalchemy flask_数据库_06

失败!!!

那就换种方法:

通过使用Christoph Gohlke收集的
非扩展Windows二进制文件Python扩展包来解决这个障碍。下载相应的mysqlclient轮(* .whl)文件。对于Python 3.7,单击“mysqlclient-1.3.13-cp37-cp37m-win_amd64.whl”,它将下载到您的计算机。然后通过以下方式手动安装pip

SQLAlchemy 对应python版本 sqlalchemy flask_User_07

 

再次运行命令:

SQLAlchemy 对应python版本 sqlalchemy flask_User_08

成功~

以后模型类有改动,比如删除或添加列,都要执行这两个命令,更新数据库表。现在在项目目录下应该自动生成了名为 dev 的数据库。
接下来执行如下命令进入 Python Shell:

python manage.py shell

创建表

使用 db.create_all() 就可以根据模型类创建表。如图:

SQLAlchemy 对应python版本 sqlalchemy flask_python_09

 

使用 db.drop_all() 方法就可以删除所有的表,但是这种方式比较粗暴,所有的数据也一同销毁了。

查询表:

SQLAlchemy 对应python版本 sqlalchemy flask_数据库_10

由于数据库是空的,所以就返回了这个

命令行就介绍到这了,接下来通过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、测试数据插入/数据更新

SQLAlchemy 对应python版本 sqlalchemy flask_数据库_11

SQLAlchemy 对应python版本 sqlalchemy flask_python_12

2、测试查询数据

SQLAlchemy 对应python版本 sqlalchemy flask_python_13

3、测试删除

SQLAlchemy 对应python版本 sqlalchemy flask_数据库_14

SQLAlchemy 对应python版本 sqlalchemy flask_User_15

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