[数据库] 数据库

1506 0
Honkers 2025-3-6 17:50:03 | 显示全部楼层 |阅读模式

数据库

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

一、 什么是ORM?

对象关系映射(英语:(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。

3.1 连接数据库:

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

  1. pip install flask-sqlalchemy
  2. pip install pymysql
复制代码

这里我们的DBMS以mysql数据库为例, 连接数据库

实例

  1. from flask import Flask
  2. from flask_sqlalchemy import SQLAlchemy
  3. app = Flask(__name__)
  4. HOST = '127.0.0.1'
  5. PORT = '3306'
  6. DATABASE_NAME = '01_db'
  7. USERNAME = 'root'
  8. PASSWORD = 'root'
  9. DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{databasename}?charset=utf8mb4"\
  10. .format(username=USERNAME,password=PASSWORD,host=HOST,port=PORT,databasename=DATABASE_NAME)
  11. app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
  12. app.config['SQLALCHEMY_TRACK_MODIFICATIONS']= False
  13. db = SQLAlchemy(app)
复制代码

解读:

1 从flask_sqlalchemy模块中导入SQLAlchemy类

  1. from flask_sqlalchemy import SQLAlchemy
复制代码

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

常用数据库的URI格式

  1. HOST = '127.0.0.1' # ip
  2. PORT = '3306' # 端口
  3. USERNAME = 'root' # 数据库账号
  4. PASSWORD = 'root' # 密码
  5. DATABASE_NAME = '01_db' # 具体的一个库名
  6. DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{databasename}?charset=utf8mb4"\
  7. .format(username=USERNAME,password=PASSWORD,host=HOST,port=PORT,databasename=DATABASE_NAME)
  8. app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
复制代码

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

  1. app.config['SQLALCHEMY_TRACK_MODIFICATIONS']= False
复制代码

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

  1. db = SQLAlchemy(app)
复制代码

3.2 数据库模型

3.2.1 什么是数据库模型?

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

3.2.2 数据库模型实例:

  1. class UserInfo(db.Model):
  2. __tablename__ = 'user_info'
  3. id = db.Column(db.Integer,primary_key=True,autoincrement=True)
  4. username = db.Column(db.String(20),nullable=False)
复制代码
    1. __tablename__
    复制代码

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

    1. __tablename__
    复制代码

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

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

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

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

3.2.3 常用的字段类型表:

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

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=‘数字’

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

  1. class UserInfo(db.Model):
  2. __tablename__ = 'user_info'
  3. id = db.Column(db.Integer,primary_key=True,autoincrement=True)
  4. username = db.Column(db.String(20),nullable=False)
  5. db.create_all()
复制代码

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

3.2.6 更新模型

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

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

3.3 数据库操作

3.3.1 增

模型表 映射到数据中

  1. class School(db.Model):
  2. __tablename__ = "school"
  3. id = db.Column(db.Integer,primary_key=True,nullable=False,autoincrement=True,comment="ID")
  4. name = db.Column(db.String(30),nullable=False,server_default='',comment="学校名称")
  5. area = db.Column(db.String(30),nullable=False,server_default='',comment="所属地区")
  6. score = db.Column(db.Integer,nullable=False,server_default='600',comment="录取分数线")
  7. def __repr__(self):
  8. return "<School(name:{})>".format(self.name)
  9. db.create_all()
复制代码
实例3.3.1.1: 新增实例

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

  1. school_01 =School(name="北京大学",area="北京",score=658) # 实例化模型类作为一条记录
  2. school_02 =School(name="清华大学",area="北京",score=667)
  3. school_03 =School(name="中山大学",area="广东",score=645)
  4. school_04 =School(name="复旦大学",area="上海",score=650)
  5. db.session.add(school_01) # 把新创建的记录添加到数据库会话
  6. db.session.add(school_02)
  7. db.session.add(school_03)
  8. db.session.add(school_04)
  9. db.session.commit() # 提交数据库会话
复制代码

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

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

查看数据库

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

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

3.3.2 查

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

  1. 模型类.<过滤方法>.<查询方法>
复制代码

常用过滤器表:

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

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

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

  1. all_school = School.query.all()
  2. print(all_school)
  3. # 输出:[<School(name:北京大学)>, <School(name:清华大学)>, <School(name:中山大学)>, <School(name:复旦大学)>]
复制代码

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

  1. school_01 =School.query.first()
  2. print(school_01)
  3. # 输出:<School(name:北京大学)>
复制代码

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

  1. school_01 = School.query.get(1)
  2. print(school_01)
  3. #输出:<School(name:北京大学)>
复制代码

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

  1. beijing_all = School.query.filter(School.area == "北京").all()
  2. beijing_first = School.query.filter(School.area == "北京").first()
  3. print(beijing_all)
  4. print(beijing_first)
  5. # 输出:[<School(name:北京大学)>, <School(name:清华大学)>]
  6. # <School(name:北京大学)>
复制代码

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

  1. zhongshan_school = School.query.filter_by(name='中山大学').all()
  2. print(zhongshan_school)
  3. # 输出:[<School(name:中山大学)>]
复制代码

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

  1. fudan_school = School.query.filter(School.name == '复旦大学').first()
  2. print(fudan_school)
  3. # 输出:<School(name:复旦大学)>
  4. fudan_school = db.session.query(School).filter(School.name == '复旦大学').first()
  5. print(fudan_school)
  6. # 输出:<School(name:复旦大学)>
复制代码

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

3.3.3 改

实例3.3.3.1: 修改实例

修改北京大学的录取成绩

  1. beida = School.query.filter(School.name=='北京大学').first()
  2. beida.score = 630
  3. db.session.commit()
复制代码

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

  1. 找到对应的记录对象

  2. 修改记录对象的属性

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

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

3.3.4 删

实例3.3.4.1: 删除实例

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

  1. qinghua = School.query.filter(School.name=='清华大学').first()
  2. db.session.delete(qinghua)
  3. db.session.commit()
复制代码

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

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行