MySQL
MySQL 社区版是开源免费的,性能也不错的,所以这里选择了MySQL 。
安装 MySQL
去MySQL 官网,进入download 模块,下载社区版,
这里安装的是MySQL5.6 版本,勾选,Next,
选择自定义安装,
可以根据自己的的情况选择,这里选择MySQL server 5.6.26 - X64 ,MySQL Workbench 6.3.4 - X64 是图形化的客户端工具,Next,
在这个界面系统会让你确认这些组件是不是你所要安装的组件,点击Execute ,执行安装完成,Next,
可以看到MySQL server 5.6.26 需要进行一个配置操作,
配置模式,这里选默认开发者机器,使用默认的端口号3306 ,Next,
设置密码,Next,
可以看到,MySQL 在Windows 上的服务名是MySQL56 ,没有必要修改,Next,
点击Execute ,之后点击Finish ,MySQL 的配置工作完成了,Next,
不勾选,就是安装完不打开图形化客户端(之后会讲解登录到MySQL 的方法),Finish 完成了安装。
登录 MySQL
这里介绍一下使用命令窗口登录MySQL ;
登录到MySQL ,首先要MySQL 服务启动才行,如果没启动那自然不行,这里说一下查看MySQL 状况的方法,
Windows 可以到这里,控制面板\所有控制面板项\管理工具,选择服务
在服务可以看到状态,如果没启动,可以右键点击MySQL 服务选择启动就可以,
MySQL 服务启动了,就可以在开始菜单选择MySQL 5.6 Command Line Client 来打开命令窗口,
打开之后输入密码,
如图登录成功,
输入exit 可以退出;
还可以使用第三方的客户端工具,Navicat 挺好用的,可以自行安装使用;
这里使用了一个叫MySQL-Front 的工具,
安装,会先让你创建一个连接,然后使用连接上填写信息去连接到MySQL 数据库,
简单说一下,名称指的是这个连接的名称,Host 是本机的话,就写127.0.0.1 ,填好密码,数据库那一栏可以不填,点击确定,完成连接的创建,
然后打开连接,界面如下,
使用 SQLAlchemy
SQLAlchemy提供了ORM,也提供了使用数据库原生SQL的功能,所以通过它,你可以用面向对象的思想处理数据库操作。
如果你需要快速的开始使用 SQLAlchemy ,那么推荐你使用Flask-SQLAlchemy 扩展。这里可以参考Flask 文档上相关部分,
使用命令安装Flask-SQLAlchemy 扩展,
pip3 install flask-sqlalchemy
使用时在Python 导入用到的模块,例如,
from flask_sqlalchemy import SQLAlchemy
用到了Flask-MySQLdb 模块,安装如下,
pip install flask-mysqldb
配置数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@127.0.0.1:3306/books_db'
可以看到,地址是由,用户名,密码,主机地址,端口与数据库名字组成的。
SQLALCHEMY_TRACK_MODIFICATIONS ,设置成True(默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
这里感觉没必要,关闭了它。
引入SQLAlchemy模块,创建对象,
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
创建数据库
这里我们可以手动去命令行创建数据库;
mysql> create database books_db;
Query OK, 1 row affected (0.03 sec)
这样在MySQL-Front可以看到books_db 数据库,
也可以在MySQL-Front 右键,新建,数据库;
创建模型
这里的模型就是对应于数据库的表,一个模型对应一张表,之前提到SQLAlchemy 提供了ORM ,这样就不用写SQL 语句就可以完成表的创建;
例如我们要创建这样的两张表,
roles (表名)
id (主键) name
1 admin (管理员)
2 user (用户)
users (表名)
id (主键) name role_id (外键)
1 小明 1
2 小哈 2
3 小红 2
roles 指明角色,管理员的意味着权限高;users 是用户表,该表role_id 觉定着用户的角色,是外键,对应于roles 的id 。
我们在Python 文件里定义两个类,Role 对应于roles 表,User 对应于users 表,都继承db.Model ,
from sqlalchemy import Column, Integer, String, ForeignKey
class Role(db.Model):
__tablename__ = 'roles'
id = Column(Integer, primary_key=True)
name = Column(String(16), unique=True)
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(16), unique=True)
role_id = Column(Integer,ForeignKey('roles.id'))
可以看到使用了一个名为ForeignKey的构造,其含义为,其所在的列的值域应当被限制在另一个表的指定列的取值范围之类,也就是外键,这样模型就创建完了。
有了模型接下来就可以创建表了,创表语句如下,
db.create_all()
如果要保证每次运行都有一个干净的表,可以先删除表,
if __name__ == '__main__':
db.drop_all()
db.create_all()
app.run(debug=True)
运行一下,在命令行查看,
mysql> use books_db
Database changed
mysql> show tables;
+--------------------+
| Tables_in_books_db |
+--------------------+
| roles |
| users |
+--------------------+
2 rows in set (0.00 sec)
mysql> desc roles;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(16) | YES | UNI | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> desc users;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(16) | YES | UNI | NULL | |
| role_id | int(11) | YES | MUL | NULL | |
+---------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
当然也可以在MySQL-Front 查看,
接下来,学习一下,增删改查,
增
role = Role(name='admin')
db.session.add(role)
db.session.commit()
user = User(name='小明', role_id=role.id)
db.session.add(user)
db.session.commit()
语句执行后,可以在命令行查看,
mysql> select * from roles;
+----+-------+
| id | name |
+----+-------+
| 1 | admin |
+----+-------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+--------+---------+
| id | name | role_id |
+----+--------+---------+
| 1 | 小明 | 1 |
+----+--------+---------+
1 row in set (0.00 sec)
删
db.session.delete(user)
db.session.commit()
user 是模型对象,对应于表里的一条数据。
改
这里改的话也比较方便的,如下,
role.name='user'
db.session.commit()
查询看一下表里的值已改了,
+----+------+
| id | name |
+----+------+
| 1 | user |
+----+------+
查
查询操作还是挺多的,这里就简单介绍几种,例如,
- 查询所有用户数据
User.query.all()
- 查询有多少个用户
User.query.count()
- 查询第一个用户
User.query.first()
- 查询某个字段为某个值的数据,
如查询id 为1 的用户,
如果要查的字段是主键可以如下,
User.query.get(1)
过滤器的用法,
若查询名字为小明的用户可以如下,
User.query.filter_by(name='小明').first()
也可以如下,
User.query.filter(User.name=='小明').first()
Demo
这里简单说一下几个点,
加密配置,
app.secret_key='books'
这里配置密钥为books 。
一个查询方式,
from sqlalchemy import exists
is_exist = db.session.query(exists().where(Author.name == author)).scalar()
直接返回bool 型,根据条件Author.name == author 去表查找,找到返回True 。
还用到两个比较重要的知识点,就是外键与关联,接下来重点说一下。
先看一下Demo 里的模型,
class Role(db.Model):
__tablename__ = 'roles'
id = Column(Integer, primary_key=True)
name = Column(String(16), unique=True)
users = relationship('User', backref='role')
# 帮助打印
def __repr__(self):
return '<Role: %s %s>' % (self.name,self.id)
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(16), unique=True)
role_id = Column(Integer, ForeignKey('roles.id'))
def __repr__(self):
return '<User: %s %s %s>' % (self.name,self.id,self.role_id)
可见于之前不同的就是,增加了relationship ,这就是关联属性的,当然使用它也要导入,
from sqlalchemy.orm import relationship
ForeignKey
外键保证数据的完整性,保证数据的一致性。
完整性:从表插入数据时会检查外键所在字段在主表里是否存在;
例如,我们这么写没问题,
user1 = User(name='小明', role_id=role1.id)
是因为role1.id 在roles 表里肯定存在, 如果你随便赋值role_id=12 ,且那个12 在roles 表里没有id 为12 的数据,那么就会报错, 可见User 表设置了ForeignKey('roles.id'),则外键role_id 不能随便赋值,且必须为roles 表里存在的id 。
一致性:删除更新主表的字段,则从表会有关联动作。
已删除为例,我们做如下操作,
role1 = Role(name='admin')
role2 = Role(name='user')
db.session.add_all([role1, role2])
db.session.commit()
user1 = User(name='小明', role_id=role1.id)
user2 = User(name='小红', role_id=role2.id)
user3 = User(name='小哈', role_id=role2.id)
db.session.add_all([user1, user2, user3])
db.session.commit()
可见。小明的role_id 为role1.id ,那如果我们只将role1 删除,会有什么现象呢?我们没有对操作,user1 对应的那条数据会怎样呢?
我们来试一下,
db.session.delete(role1)
db.session.commit()
查看数据表,
mysql> select * from roles;
+----+------+
| id | name |
+----+------+
| 2 | user |
+----+------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+--------+---------+
| id | name | role_id |
+----+--------+---------+
| 1 | 小明 | NULL |
| 2 | 小红 | 2 |
| 3 | 小哈 | 2 |
+----+--------+---------+
3 rows in set (0.00 sec)
可见roles 表,只有id 为2 的user数据了,因为我们把admin 的数据删除了,
还有,users 表第一条name 为小明的数据的role_id 的值为NULL 了,
可以外键的一致性使users 表里不会出现role_id 的值在roles 表里不存在的那种不一致的现象。
relationship
在数据结构上外键对连表查询并没有太多的帮助,但在sqlalchemy的模型下外键对连表查询有一定的优化,那就是relationship字段,其配合外键一起使用。
没有用relationship 想要查询user1 的角色,分为两步,
- 先查出user1 的role_id ;
- 在roles 表根据id 查出角色值;
有了relationship之后就不用分为两步走了,只需要一步就能搞定。在定义表的模型时,relationship将roles 与users 表关联在一起,看一下Role 模型这句,
users = relationship('User', backref='roles')
roles 表与users 表关联,backref是反向关联(反向引用),在关系的另一个模型里添加反向引用,
就是这里我们可以这样去理解,
users 在Role 类里,所以是该类的一个属性(不是表的字段),
roles 是反向引用(backref='roles'),所以是User 类的一个属性(不是表的字段),
接下来说一下其使用。
正向查询
print(User.query.get(1))
print(User.query.get(1).roles.name)
输出如下,
<User: 小明 1 1>
admin
roles是主表,users 是从表,通过User1.roles 查到外键关联的roles 表的数据,查users 表返回roles 表的数据,称之为,正向查询。
反向查询
print(Role.query.get(2))
print(Role.query.get(2).users)
print(Role.query.get(2).users[0])
print(Role.query.get(2).users[0].name)
输出如下,
<Role: user 2>
[<User: 小红 2 2>, <User: 小哈 3 2>]
<User: 小红 2 2>
小红
roles是主表,users 是从表,通过role2.users 查到外键关联的users 表的数据,查roles 表返回users 表的数据,称之为,反向查询。