数据库
1、数据库的安装与配置
这节用到flask的两个扩展,使用pip安装扩展就行
pip install flask-sqlalchemy pip install flask-mysqldb
然而,扩展只是基于数据库的一个抽象工具,就是说它只能让你的数据库更好用,但它本身并不是数据库。在使用这两个扩展之前,你还需要安装一个MySQL数据库。
参考:MySQL数据库安装教程(详细)
按教程中的压缩包方法,反正我安装成功了,如果遇到问题,可以翻翻评论区试试。
完成安装和配置后,数据库本地服务的启动流程:
# 1.登录数据库:打开cmd,输入下面命令。成功后会显示一段Welcome的话 C:\Users\ThinkPad>mysql -u用户名 -p 密码 # 2. 创建数据库:如果创建过,可跳过 mysql> create database flask_sql_demo charset=utf8; # 3. 启动已创建的数据库 mysql> use flask_sql_demo;
MySQL较常见的一些命令:
# 1. 显示所有表单名 mysql> show tables; # 2. 查看一个表单的字段结构(数据字典) mysql> desc 表单名; # 3. 查看一个表单的内容 mysql> select * from 表单名; # 4. 关闭数据库 --> 显示Bye mysql> quit # 5. 显示所有数据库 mysql> show databases; # 6. 删除数据表 mysql> drop table 数据表名; # 7. 删除数据库 mysql> drop database 数据库名;
2、数据库的简单使用——增删改
1. 定义数据模型
增删改的操作对象是数据表,所谓“定义数据模型”,应该就是定义表的结构。
运行代码前,并不需要在终端登录数据库,脚本中本身就会登录。在终端登录数据库可以方便查看数据库的状态。
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # 配置数据库的地址,url结构为'mysql://用户名:密码@IP地址/数据库名' app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:写你的密码@127.0.0.1/flask_sql_demo2' # 数据库实例 db = SQLAlchemy(app) ''' 两张表 角色(管理员,普通用户) 用户(角色id) ''' # 数据库的模型,需要继承db.Model class Role(db.Model): # 定义表名 __tablename__ = 'roles' # 定义字段 --> db.Column表示是一个字段 id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True) class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True) email = db.Column(db.String(32),unique=True) password = db.Column(db.String(32)) # db.ForeignKey('roles.id'),表示是外键,表名.id role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) # -- main -- ctx = app.app_context() ctx.push() db.drop_all() # 删除旧表 db.create_all() # 创建新表 ctx.pop()
然后可以在终端使用mysql命令查看创建的表单
mysql> show tables; +---------------------------+ | Tables_in_flask_sql_demo2 | +---------------------------+ | roles | | users | +---------------------------+ 2 rows in set (0.00 sec)
2. 增删改
Flask-SQLAlchemy的数据是有会话(Session)管理的,在增、删或修改操作后,都需要有一个提交步骤,然后变更才会在数据库中生效。
1、增加数据
ro1 = Role(name='admin') db.session.add(ro1) db.session.commit()
也可以批量添加提交数据
ro1 = Role(name='admin') ro2 = Role(name='user') db.session.add_all([ro1, ro2]) db.session.commit()
2、修改数据
ro1.name = 'other' db.session.commit()
3、删除数据
db.session.delete(ro1) db.session.commit()
3、 关系引用——表的关联
我们之前定义的表users
中,有一个外键role_id
,是关联到表roles
的。如果要从表users中要得到一个用户的角色的名字,就只能先得到角色的id,然后拿着这个id再到roles表中去找角色的名字,就是说需要经过两次查询。
“关系引用”的
- 作用:上述过程我只需要一次查询就可以得到用户的角色名。
- 条件:需要是“一对多”的关系;例如很多用户有相同的角色名,但一个用户只能有一个角色名;这里角色名就是“一”,用户就是“多”。
- 创建:在作为“一”的一方写关联。
创建roles表和users表之间的关联,我只需要修改类Role的定义就可以了。
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True) # 在"一"的一方,写关联 # Role表增加了一个users属性 # backref='role':表示role也是User要用的属性(回关) users = db.relationship('User', backref='role')
关联的属性不会出现在数据库的表中,我们可以通过类名.属性名
的方式来访问一个表的属性,例如
print(ro1.users)
输出的效果是这样子(下面的输出仅用于展示格式),它仅显示了类型和id,
[<User 1>, <User 2>]
如果我希望显示用户的具体信息,则需要在类的定义中加入__ref__
方法,例如在类User
中加入,
class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True) email = db.Column(db.String(32),unique=True) password = db.Column(db.String(32)) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) # 类的实例返回字符串 def __repr__(self) -> str: return '<User: %s %s %s %s %s>' % (self.id, self.name, self.email, self.password, self.role_id)
则表的属性显示效果将是
[<User: 1 wang wang@123.com None 1>, <User: 2 zhang zhang@123.com None 1>]
4、查询——通过SQLAlchemy扩展
过滤器和执行器,过滤器仅对数据进行筛选,返回结果还需使用执行器。
查询users表中的所有对象
User.query.all()
查询users表中id为4的对象
# 1. 旧的,已弃用 User.query.get(4) # 2. filter_by --> 属性=值 User.query.filter_by(id=4).first() # 3. filter --> 类.属性==值; 更加灵活,支持比较运算符 User.query.filter(User.id==4).first()
5、其他
1. 数据模型的实现(疑惑)
感觉有些奇怪,在定义一个数据模型类时,我仅仅需要在类中定义一些变量,如__tablename__
,id
,name
,
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True)
后面创建数据时就可以使用这些变量名作为关键字参数传参,
ro1 = Role(name='admin')
6、Bug记录
1. 1045,"Access denied for user ‘root’@‘localhost’ "(using password: YES)
当时我在cmd可以登录数据库,可当我运行python脚本时,就报出这个错误,查了许多文章都没有解决。后来有次在终端输错了密码发现也是报这个错误,于是发现是配置数据库地址的问题,
root:mysql
中的mysql
是密码,我还以为是固定的语法就照写了。
# 错误写法 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1/flask_sql_demo2' # 修改 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:我的密码@127.0.0.1/flask_sql_demo2'
2. RuntimeError: Working outside of application context
发现脚本中对数据库的操作就会引发改问题,一个较方便的处理方式是
ctx = app.app_context() ctx.push() 数据库操作 ctx.pop()