liuweiq 2020-06-14
ORM
对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中
一种设计思想,以面向对象形式操作数据库,将增删改查包装成了方法,不用sql语句(自动生成sql语句),可以根据实体类的映射创建表
Flask-sqlalchemy
SQLAlchemy是Python开发的一个实现了ORM思想的模块,将Python面向对象的类映射为数据库的表,通过映射关系来完成数据库的操作,降低数据库操作的难度和繁琐程度
Flask-SQLAlchemy 是一个为 Flask应用增加 SQLAlchemy支持的扩展。它致力于简化在 Flask中SQLAlchemy 的使用,提供了有用的默认值和额外的API来更简单地完成常见任务
安装flask-sqlalchemy
pip install flask-sqlalchemy
简单使用
链接sqlite数据库
这是一个文件型数据库,用于微小型测试项目,正式项目使用mysql
将生成是sqlalchemy文件拖到dabase面板中就可以打开了
注意:点击Test Connectction,下载 Driver Files
# 导入包 from flask import Flask from flask_sqlalchemy import SQLAlchemy import os import pymysql pymysql.install_as_MySQLdb() # 创建flask的实例 app = Flask(__name__) # 获取项目所在目录的绝对路径 BASE_DIR = os.path.abspath(os.path.dirname(__file__)) # 配置sqlite数据库的URI app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(BASE_DIR, "db.sqlite") # 配置Mysql数据库的URL # app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:/oa" # 配置动态追踪修改设置 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True # 查看映射的sql语句 app.config["SQLALCHEMY_ECHO"] = True # 创建sqlalchemy的核心对象 db = SQLAlchemy(app) class Person(db.Model): id = db.Column(db.INT, primary_key=True, autoincrement=True) username = db.Column(db.VARCHAR(100)) # 同步数据库,如果表已经创建,忽略 db.create_all()
链接 Mysql 数据库
链接mysql数据库
(1) 需要安装依赖pymysql
pip install pymysql
(2) 数据库中创建一个数据库
create database oa default charset=utf8;
(3) 使用flask-sqlalchemy连接mysql数据库
mysql://root:/oa
mysql://用户名:密码@主机ip/数据库名
(4) 运行项目
执行create_all方法能将创建的模型类同步到表结构
注意:create_all方法只能够将新创建的模型同步表结构,如果模型修改或者删除,create_all不会同步
字段和属性
__ tablename __:定义表的名称
字段的类型
类型 | 描述 |
---|---|
Integer | 整型 |
Float | 浮点型整型 |
Date | 时间类型年月日 |
DateTime | 时间类型 年月日时分秒 |
Text | 长文本 |
String | 变长字符串 |
?
常见字段属性
属性 | 描述 |
---|---|
primary_key | 主键 |
unique | 键值唯一性 |
index | 索引 |
nullable | 空值 |
default | 默认值 |
数据库学习难度不在基本语句,增删改查。对于开发来说,数据建模时相当有挑战性的,所谓的数据库建模:就是用数据库来描述业务逻辑,一个好的数据库模型代表整个网站成功一半,反之,如果数据库设计出了问题,项目多半不会成功
建模需要描述的内容
? 业务主体:就是在这个网站当中的对象
? 主体关系:对象之间的联系
比如 : OA系统
? 需要有员工数据表
? 需要有职位数据表
? 需要有部门数据表
? 首先使用字段来描述 员工,职位,部门
? 其次需要使用字段描述:
? 员工和职位是 多对一关系
? 部门和职位是 一对多关系
当前所有的内容,包括视图、链接数据库及模型部分都在同一个文件中。这种单文件编程显示是不合理的,我们在学习如何链接数据库及模型中的常用属性后,要将模型放在项目中,首先优化我们的目录结构,将视图,配置信息,模型分别独立出来
app.py项目初始化,配置文件
modles.py模型文件
viwes.py视图文件
mian.py项目控制文件
单表操作
(1) 增加单条数据
@app.route("/add/person") def add_person(): """新增""" # 创建对象 p = Person( username="小王", password="123456" ) # 增加 db.session.add(p) # 提交,增删改需要提交才会生效 db.session.commit() return "add_person"
(2) 增加多条数据
@app.route("/add/person") def add_person(): """新增""" # 创建对象 p = Person( username="小王", password="123456" ) p2 = Person( username="小赵", password="123456" ) # 增加 db.session.add_all([p,p2]) # 提交,增删改需要提交才会生效 db.session.commit() return "add_person"
(3) 查询
方法 | 说明 | 例子 |
---|---|---|
all | 查询符合条件的所有内容,返回值为列表,没有值返回空列表 | 查询当前所有员工person_list = Person.query.all() |
get | 通过id进行查找,返回值为对象,没有值返回None | 查id为288的员工person= Person.query.get(288) |
filter | 过滤筛选 | ##查所有男生 person_list = Person.query.filter_by(gender = "男") |
filter_by | 过滤筛选 | #查所有年龄大于21岁的男同事 person_list = Person.query.filter(Person.age > 21,Person.gender=="男") |
like | 模糊查询% 匹配0个或者多个_ 匹配一个 | # 查所有年龄大于21岁的吴姓男同事 person_list = Person.query.filter( Person.age > 21, Person.gender=="男", Person.nickname.like("吴%") ) |
limit | 返回的数据的条数 | # 查10位年龄大于21岁的男同事 person_list = Person.query.filter( Person.age > 21, Person.gender=="男" ).limit(10) |
offset | 查询起始位置,以下标进行偏移 | # 从第二十个开始,查询10位年龄大于21岁的男同事 person_list = Person.query.filter( Person.age > 21, Person.gender=="男" ).limit(10).offset(20) |
order_by | 排序 | # 按照年龄排序,查询所有吴姓男同事,正序 person_list = Person.query.filter( Person.gender=="男", Person.nickname.like("吴%") ).order_by(Person.age) |
max min count sum avg | 聚合查询 | #查询所有吴姓男生的个数from sqlalchemy import func result = db.session.query(func.count(Person.id) ).filter(Person.gender == "男",Person.nickname.like("吴%")).all() |
group_by | 分组 | #分组查询 from sqlalchemy import func #查询男女个数 result = db.session.query( Person.gender, func.count(Person.id) ).group_by(Person.gender).all() #查询年龄个数 result = db.session.query( Person.age, func.count(Person.id) ).group_by(Person.age).all() print(result) |
and_or_not_ | 逻辑查询 导入from sqlalchemy import and_,or_,not_ | # 查询所有吴姓男生 person_list = Person.query.filter( Person.gender"男", Person.nickname.like("吴%") ) #查询所有吴姓同事或者男同事 person_list = Person.query.filter( or_( Person.gender"男", Person.nickname.like("吴%") ) ) |
(4)修改
@app.route("/update") def update(): """修改""" # 查询 person = Person.query.get(1) if person: # 修改 person.password = 33 # 提交,增删改需要提交才会生效 db.session.commit() return "update"
(5) 删除
@app.route("/delete") def delete(): """修改""" # 查询 person = Person.query.get(1) if person: # 删除 db.session.delete(person) # 提交,增删改需要提交才会生效 db.session.commit() return "delete"
封装
(1) 每个模型都要创建一个id字段,基于面向对象的思想,将冗余的代码封装到一个父类
(2) 所有的模型都需要增删改方法
class Base(db.Model): """基类""" # 作为父类被继承,不会被创建成表(抽象) __abstract__ = True id = db.Column(db.Integer, primary_key=True, autoincrement=True) # id def save(self): db.session.add(self) db.session.commit() def delete(self): db.session.delete(self) db.session.commit() def update(self): db.session.commit()
我们已经了解如何进行数据库的搭建和基本的增删改查,但是在数据库建模的过程当中,不止有基于业务主体描述数据库模型,还有关系模型,常用的关系有以下两种
1、一对多关系
例如:职位和员工是一对多关系,一个员工可以有一个职位,一个职位可以对应多个员工
在数据库当中,通常采用外键来进行一对多约束。使用foreign-key就可以达成外键
(1)模型搭建
在多表当中创建一个字段,定义为int类型,用来存储一表的id,一表表名小写
position_id = db.Column(db.Integer,db.ForeignKey("position.id"))
在一表当中,创建字段反向映射向多表。backref是在多表当中操作一表数据的字段。
persons = db.relationship("Person", backref="position")
relationship:只是单纯的表现了两个模型类之间的关系,并不会体现在数据库的表结构中,只是为了在进行一对多的查询中更加的方便使用。在本例中:persons 用来一表反查多表、Person多表类名、backref 是多表查询一表的对应数据的字段
注:一对一关系只需要增加列表项: uselist=Flase 即可
2、多对多关系
在OA项目中,还有权限管理
首先主任有查看部门考勤和组织部门会议的权限
经理具有查看部门考勤,组织部门会议,招聘员工,开除员工的权限
表一:描述职位,例如:职位名称,职位等级
表二:描述权限,例如:权限名称
表一和表二是多对多的关系,一个职位可以有多种权限,一种权限可以给多个职位