数据库

数据库

数据库,顾名思义是储存数据的仓库,常见的管理数据库的软件被称为数据库管理系统(DBMS, Database Management System), 常见的DBMS有 MySQL、PostgreSQL、SQLite、MongoDB。这些常见的DBMS我们可以把他们理解为专门负责搬运数据的管理的数据的程序。
1554281623399

一、 什么是ORM?

img

对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 。 ORM是“对象-关系-映射”的简称。在我们的web应用开发中ORM把底层的SQL数据实体转化成高层的Python对象。只需要通过Python代码即可完成数据库操作。

二、 为什么要有ORM?

在web应用里使用原生的SQL语句操作数据库固然能达到我们处理储存数据的需求,但是会存在以下三类问题:

  • 手动编写SQL语句比较复杂耗时(当然因人而异,如果热衷于原生sql,并不影响开发),并且视图函数中写大量SQL语句会降低代码的易读性。
  • 比较容易出现安全问题,如SQL注入。
  • 对于不同的DBMS,需要使用不同的Python接口库,语法各不相同,很难有标准化的代码流程。

使用ORM可以很大程度上解决这些问题,在python中,ORM把底层的SQL数据实体转化成高层的Python对象。这样的好处是,你甚至不需要了解SQL,只需要操作Python对象的即可完成数据库操作。

使用ORM的优势:

  • 提升开发效率。从高层对象转换成原生SQL会牺牲一些性能,但这微不足道的性能牺牲换取的是巨大开发效率提升。
  • 可移植性好。它实现了数据库模型与DEMS的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库。通常一个orm支持很多的DEMS,如1MySQL、PostgreSQL、Oracle、SQLite等,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。

三、 如何在Flask应用ORM?

选择ORM框架时,在我们Flask中更推荐使用Flask的扩展组件Flask-SQLchemy 。Python实现的ORM有SQLAlchemy、Peewee、PonyORM等,其中SQLAlchemy是Python社区使用最广泛的ORM之一,Flask-SQLchemy正是基于SQLchemy。

img

3.1 连接数据库:

首先切入到我们的虚拟环境 ,安装我们的 Flask-SQLchemy

pip install flask-sqlalchemy
pip install pymysql

这里我们的DBMSmysql数据库为例, 连接数据库

实例

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
HOST = '127.0.0.1'
PORT = '3306'
DATABASE_NAME = '01_db'
USERNAME = 'root'
PASSWORD = 'root'

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{databasename}?charset=utf8mb4"\
.format(username=USERNAME,password=PASSWORD,host=HOST,port=PORT,databasename=DATABASE_NAME)

app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']= False


db = SQLAlchemy(app)

解读:

1flask_sqlalchemy模块中导入SQLAlchemy

from flask_sqlalchemy import SQLAlchemy

2 app对象通过变量SQLALCHEMY_DATABASE_URI加载配置好的URI(统一资源标识符),URI内包含了各种用于连接数据库的信息,指向一个具体的库。

常用数据库的URI格式

HOST = '127.0.0.1'  # ip
PORT = '3306'       # 端口
USERNAME = 'root'   # 数据库账号
PASSWORD = 'root'   # 密码
DATABASE_NAME = '01_db'  # 具体的一个库名
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{databasename}?charset=utf8mb4"\
.format(username=USERNAME,password=PASSWORD,host=HOST,port=PORT,databasename=DATABASE_NAME)

app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI

3 SQLALCHEMY_TRACK_MODIFICATIONS这个配置变量决定是否追踪对象的修改,这用于FLask- SQLALchemy的事件通知系统。这个配置键默认值为None,如果没有特殊需要我们把它设置为Flase, 避免造成一些没必要的性能浪费。

app.config['SQLALCHEMY_TRACK_MODIFICATIONS']= False

4 SQLAlchemy类传入app类,引用app配置定位到具体的数据库,并且实例化出db对象,这个db对象代表我们的数据库,并且通过这个对象操作我们的ORM

db = SQLAlchemy(app)

3.2 数据库模型

1554281734348

3.2.1 什么是数据库模型?

继承了db.Model的python类,并且这个python类映射到数据库为一个表,这个python类称之为数据库模型。每个数据库模型都对应着数据库中的一个表。

3.2.2 数据库模型实例:

class UserInfo(db.Model):
    __tablename__ = 'user_info'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
  • __tablename__
    

    可以直接指定表名(推荐使用)。如果没有写

    __tablename__
    

    指定表名,此类名可以自动转化为表名(不推荐使用)。

    • 类名自动转化表名的方式为User–> user# 单个单词转换为小写
      UserInfo–> user_info# 多个单词转换为小写并使用下划线分隔
    • 如UserInfo类在没有__tablename__指定表名时候,UserInfo类会自动映射到数据库的表名为user_info
  • db.Column
    

    类实例化表示字段(表示数据库中的列),该类实例化出的对象被一个变量接受,该变量表示字段名。该类实例化时传入的参数表示字段的约束。

    • 如:id = db.Column(db.Integer,primary_key=True,autoincrement=True)表示该表内id字段为主键并且自动增长。

1554281780499

3.2.3 常用的字段类型表:

字段说明映射到数据库对应类型
Integer整数int类型
String字符串,String类内可选择length参数的值用于设置最大字符个数varchar类型
Text用于储存较长的Unicode文本,,理论上可以储存65535个字节text类型
Date日期,存储Pythondatetime.date 对象date类型
Time时间,存储Pythondatetime.time 对象time类型
DateTime时间和日期,存储Pythondatetime 对象datetime类型
Float浮点类型float类型
Double双精度浮点类型,比浮点类型小数位精度更高。double类型,占据64位。
Boolean布尔值tinyint类型
Enum枚举类型enum类型

img

3.2.4 Column常用参数表:

约束说明
primary_key如果设为True,该列就是表的主键
unique如果设为True,该列每个值唯一,也就是该字段不允许出现重复值
index如果设为True,为这列创建索引,用于提升查询效率
nullable如果设为True,这列允许使用空值,反之则不允许使用空值。
server_default为这列定义默认值, 默认值只支持字符串,其他类型需要db.text()方法指定
default为这列定义默认值,但是该约束并不会真正映射到表结构中,该约束只会在ORM层面实现(不推荐使用)
comment该字段的注释
name可以使用该参数直接指定字段名
autoincrement设置这个字段为自动增长的。
server_default常用配置
配置默认值类型代码
更新datatime时间server_default = db.text(“CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”)
当前的datatime时间server_default = db.text(“CURRENT_TIMESTAMP”)
数字server_default=“数字”
布尔server_default=db.text(‘True’) / server_default=db.text(‘False’)/ server_default=‘数字’

1554281889712

3.2.5 将写好的模型映射到数据库。

class UserInfo(db.Model):
    __tablename__ = 'user_info'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    
db.create_all()

如果你已经定义好了一个继承db.Model的类,我们把这个类称之为模型。我们想把这个模型映射到数据库中,也就是在数据库中创建这个模型所描述的一张表,使用db.create_all()可以实现把继承了该db.model的所有模型创建到数据库中。查看数据库的时候我们会发现多了一张user_info表。

1549800892083

3.2.6 更新模型

如果我们要更新一个模型,并且想把这个新的模型映射到数据库中,直接使用db.create_all()会无效,因为原来已经存在了这张表,为了解决这个问题我们可以先db.drop_all()删除该库下的所有继承了db.model的模型表,然后再db.create_all()使得继承了db.model的所有模型表映射到数据库中,从而创建我们更新的表。这种方式的原理是先删除数据库中原来所有的模型表,然后在新建所有需要映射的模型表,这种方式的弊端是它把数据库中原有的数据都销毁了。

为了解决这种更新模型导致删除掉原来的数据的弊端。下一章将会介绍一种更好的方式用于更新数据库。

1554281934788

3.3 数据库操作

img

3.3.1 增

模型表 映射到数据中

class School(db.Model):
    __tablename__ = "school"
    id = db.Column(db.Integer,primary_key=True,nullable=False,autoincrement=True,comment="ID")
    name = db.Column(db.String(30),nullable=False,server_default='',comment="学校名称")
    area = db.Column(db.String(30),nullable=False,server_default='',comment="所属地区")
    score = db.Column(db.Integer,nullable=False,server_default='600',comment="录取分数线")
    def __repr__(self):
        return "<School(name:{})>".format(self.name)

db.create_all()
实例3.3.1.1: 新增实例

新增四条记录映射到数据库中

school_01 =School(name="北京大学",area="北京",score=658)  # 实例化模型类作为一条记录
school_02 =School(name="清华大学",area="北京",score=667)
school_03 =School(name="中山大学",area="广东",score=645)
school_04 =School(name="复旦大学",area="上海",score=650)

db.session.add(school_01)   # 把新创建的记录添加到数据库会话
db.session.add(school_02)
db.session.add(school_03)
db.session.add(school_04)

db.session.commit()  # 提交数据库会话

提示:数据库会话db.session和后面介绍的Flasksession对象没有关系。db.session是数据库会话也称为事务。

  1. 实例化模型类创建对象,该对象作为一条记录,实例化的过程传入的参数为字段内容。
  2. 把新创建的记录添加到数据库会话。
  3. 提交数据库会话

查看数据库

1549869497823

提示1 :如果add多条记录可以使用add_all()一次添加包含多条记录的列表

如:db.session.add_all([school_01,school_02,school_03,school_04])

3.3.2 查

img

在我们的flask中db.session出的对象调用query属性,可以通过query属性调用各种过滤方法完成查询。

模型类.<过滤方法>.<查询方法>

常用过滤器表:

过滤器说明
filter()使用指定的规则过滤记录相当于sql的where约束条件,返回一个新查询
filter_by()同filter原理,不同的是查询的时要使用关键字参数,返回一个新查询
limit()使用指定的值限制原查询返回的结果的数量,返回一个新查询
offset()偏移原查询返回的结果,返回一个新查询
order_by()根据指定条件对原查询结构进行排序,返回一个新查询
group_by()根据指定条件对原来查询结构进行分组,返回一个新查询
实例3.3.2.1: 查询实例

下面几个查询案例需要在实例3.3.1完成的基础上操作

all()返回一个列表,列表里存放所有符合条件的记录

all_school = School.query.all()
print(all_school) 

# 输出:[<School(name:北京大学)>, <School(name:清华大学)>, <School(name:中山大学)>, <School(name:复旦大学)>]

first()返回符合条件的第一条记录:

school_01 =School.query.first()
print(school_01)

# 输出:<School(name:北京大学)>

get()返回指定主键值(id字段)的记录:

school_01 = School.query.get(1)
print(school_01)

#输出:<School(name:北京大学)>

filter() 使用指定的规则过滤记录相当于sql的where约束条件,返回新产生的查询对象。

beijing_all = School.query.filter(School.area == "北京").all()
beijing_first = School.query.filter(School.area == "北京").first()
print(beijing_all)
print(beijing_first)

# 输出:[<School(name:北京大学)>, <School(name:清华大学)>]
#       <School(name:北京大学)>

filter_by:同filter()效果一样,查询的时候使用关键字参数查询(无法进行多表复杂查询,不推荐使用)

zhongshan_school = School.query.filter_by(name='中山大学').all()
print(zhongshan_school)

# 输出:[<School(name:中山大学)>]

db.session.qury(模型类)等价于模型类.query,db.session.qury功能更强大一些,可以进行多表查询。

fudan_school = School.query.filter(School.name == '复旦大学').first()
print(fudan_school)  
# 输出:<School(name:复旦大学)>

fudan_school = db.session.query(School).filter(School.name == '复旦大学').first()
print(fudan_school)
# 输出:<School(name:复旦大学)>

提示:其他的过滤器会在接下来的章节具体根据实际案例讲解

3.3.3 改

实例3.3.3.1: 修改实例

修改北京大学的录取成绩

beida = School.query.filter(School.name=='北京大学').first()
beida.score = 630
db.session.commit()

1549872535950

更新一条记录分为一下几部:

  1. 找到对应的记录对象

  2. 修改记录对象的属性

  3. 直接调用db.session.commit()提交会话

    提示:只有要插入新的记录或要将现有的记录添加到会话中时才需要使用add()方法。只是更新现有记录的时可以修改记录对象属性后直接提交会话

3.3.4 删

img

实例3.3.4.1: 删除实例

从数据库中删除清华大学相关信息

qinghua = School.query.filter(School.name=='清华大学').first()
db.session.delete(qinghua)
db.session.commit()

1549872948198

删除一条记录分为以下几步:

  1. 找到对应的记录对象
  2. 需要调用delete()方法在会话中标识需要删除的记录,具体是把该记录对象传入db.session.delete(记录对象)实现标识。
  3. 调用db.session.commit()提交会话。

1554281987538

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值