一、Flask-SQLAlchemy
1、ORM 框架
Web开发中,一个重要的组成部分便是数据库了。Web程序中最常用的莫过于关系型数据库了,也称SQL数据库。另外,文档数据库(如 mongodb)、键值对数据库(如redis)近几年也逐渐在 web开发中流行起来,我们习惯把这两种数据库称为NoSQL数据库。
大多数的关系型数据库引擎(比如MySQL、Postgres和SQLite)都有对应的Python包。在这里,我们不直接使用这些数据库引擎提供的 Python包,而是使用对象关系映射(Object-Relational Mapper,ORM)框架,它将低层的数据库操作指令抽象成高层的面向对象操作。也就是说,如果我们直接使用数据库引擎,我们就要写SQL操作语句,但是,如果我们使用了ORM框架,我们对诸如表、文档此类的数据库实体就可以简化成对Python对象的操作。Python中最广泛使用的ORM框架是SQLAlchemy,它是一个很强大的关系型数据库框架,不仅支持高层的ORM,也支持使用低层的SQL操作,另外,它也支持多种数据库引擎,如MySQL、Postgres和SQLite等。
2、Flask-SQLAlchemy
在Flask中,为了简化配置和操作,我们使用的ORM框架是Flask-SQLAlchemy,这个Flask扩展封装了SQLAlchemy框架。在Flask-SQLAlchemy中,数据库使用URL指定,下表列出了常见的数据库引擎和对应的 URL。
3、安装
首先,我们使用pip安装Flask-SQLAlchemy,安装在你所需要的环境中,本作者使用的是虚拟环境,虚拟环境能比较好的解决依赖问题,
pip install flask-sqlalchemy
4、应用
1)链接数据库
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:yutao@127.0.0.1/TodoProject"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# app.config['SECRET_KEY'] = 'westos'
app.config['SECRET_KEY'] = os.urandom(24)
Bootstrap(app)
# 实例化db对象
db = SQLAlchemy(app)
这里有几点需要注意的是:
1、app应用配置项SQLALCHEMY_DATABASE_URI指定了SQLAlchemy所要操作的数据库,这里我们使用的是mysql数据库,引号里是你需要链接的数据库://用户名和密码@本机localhost或远程链接某个数据库,/后面是你要链接数据库的名称;这里特别说一点就是数据库的编码格式问题,当你在创建数据库时可以使用下面这个命令来解决你的编码问题;
create database 数据库名称 default charset utf8;
'SQLALCHEMY_DATABASE_URI' =====》链接 数据库;
'SQLALCHEMY_TRACK_MODIFICATIONS' ======》Ture
'SECRET_KEY' =====》加密
2、db 对象是 SQLAlchemy 类的实例,表示程序使用的数据库。
3、我们定义的User模型必须继承自db.Model,这里的模型其实就对应着数据库中的表。其中,类变量 __tablename__ 定义了在数据库中使用的表名,如果该变量没有被定义,Flask-SQLAlchemy会使用一个默认名字。
2)建表
在这里我们的建表有了突破性的进展,前面我们一直说mysql是一个关系型数据库,但是没有体现出“关系”二字,在这里我们就要建立有关系的数据表;
我们设想这样的一个场景:我们在公司的内部系统上每一天都会有任务发布,有任务本身和它相关的执行部门,他们两个关系在任务产生的时候就被绑定在了一起,这样也就完成了我们所说的关系,那么我们在数据库中怎样建立数据表之间的关系呢?
外键约束是在两张表中建立的。两张表存在父子关系,即:子表中的某个字段的取值有父表决定的。
结论:在一对多关系中额,外键建立在多的一方
例如:简单的例子在很多的电影网站上都有会员,超级会员,普通会员这三种会员身份,我们需要对普通用户的身份进行关联
# 创建user表
class Users(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
# unique: 指定该列信息是唯一的;
name = db.Column(db.String(50), unique=True)
passwd = db.Column(db.String(50))
# default是默认值l
add_time = db.Column(db.DateTime, default=datetime.now())
role_id = db.Column(db.Integer, db.ForeignKey('role.id')) #和哪张表的哪个表头进行关联
# 创建用户角色(超级会员, 会员, 普通会员)
class Role(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.String(50), unique=True)
# 'Users代表的是Role表关联的数据库表'
# backref=“role”: 反向引用;让Users中有role属性, user.role返回的是role对象。
users = db.relationship('Users', backref='role') #上表和这里的进行相关联
#
# def __repr__(self):
# """如果查询数据表内容, 需要特色化设置时, 使用__repr__"""
# return "<Role %s>" %(self.name)
# 1. 创建表
# db.create_all()
下面的是我们更为复杂的例子:
class Todo(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
# unique: 指定该列信息是唯一的;
name = db.Column(db.String(50))
# default是默认值l
add_time = db.Column(db.DateTime, default=datetime.now())
status = db.Column(db.Boolean, default=False)
department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
class Department(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.String(50), unique=True)
todos = db.relationship('Todo', backref='department')
users = db.relationship('User', backref='department')
class User(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
# unique: 指定该列信息是唯一的;
name = db.Column(db.String(50), unique=True)
# 此处为了用户帐号的安全性, 必须对密码进行加密;
pwd = db.Column(db.String(100))
email = db.Column(db.String(20), unique=True)
phone = db.Column(db.String(20), unique=True)
info = db.Column(db.Text) # 个性简介
addtime = db.Column(db.DateTime, default=datetime.now())
department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
userlogs = db.relationship('UserLog', backref="user")
def check_pwd(self, pwd):
return check_password_hash(self.pwd, 'westos1')
# 用户登录日志
class UserLog(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
ip = db.Column(db.String(100)) # 登录的IP
addtime = db.Column(db.DateTime, default=datetime.now())
area = db.Column(db.String(100)) # 登录的城市
3)给表中添加信息
1、建表
# 1). 创建表
# db.create_all()
2、给表内添加信息
2). 初始化数据
parts = ['开发部', '运维部', '人事部']
partObj = [Department(name=part) for part in parts]
db.session.add_all(partObj)
db.session.commit()
todos = ['打扫卫生', '开发微电影管理系统', '招聘人才']
todoObj = [Todo(name=todo, department_id=random.choice([1,2,3]) ) for todo in todos]
db.session.add_all(todoObj)
db.session.commit()
3、添加用户的测试数据
u1 = User(name=