Flask狼书笔记 | 05_数据库

请添加图片描述

文章目录

  • 5 数据库
    • 5.1 数据库的分类
    • 5.2 ORM
    • 5.3 使用Flask_SQLAlchemy
    • 5.4 数据库操作
    • 5.5 定义关系
    • 5.6 更新数据库表
    • 5.7 数据库进阶
    • 小结

5 数据库

这一章学习如何在Python中使用DBMS(数据库管理系统),来对数据库进行管理和操作。本书使用SQLite作为示例。

:按下Ctrl+F5,或Shift+F5可以清除浏览器缓存。

5.1 数据库的分类

分为SQL(Structured Query Language)数据库和NoSQL(Not Only SQL)数据库。

  • SQL:稍显复杂,但不容易出错,可以适应大部分场景。
  • NoSQL:灵活,效率高,可扩展性好等。
    • 1、文档存储:使用类json格式来表示数据
    • 2、键值对存储:通过键来存取数据,读写很快,常作为缓存使用。

5.2 ORM

ORM:Object-Relational Mapping,对象关系映射。

作用

  • 处理查询参数的转义,防止注入。
  • 为不同的DBMS提供统一的接口。
  • 能直接使用Python操作数据库,不需要写SQL语句。

ORM实现了三层映射关系:表 --> Python类,字段 --> 类属性,记录 --> 类实例。

# 定义表
from foo_orm import Model, Column, String 
class Contact(Model):__tablename__ = 'contacts'name = Column(String(100), nullable=False)# 插入记录
contact = Contact(name="zhang san")

5.3 使用Flask_SQLAlchemy

1、连接数据库

首先连接数据库需要指定URI(Uniform Resource Identifier,统一资源标识符),URL(统一资源定位符)是它的子集。

常用的数据库URI格式:(p143)

SQLite是基于文件的DBMS,不需要数据库服务器,只需要指定数据库文件的绝对路径。配置数据库URI的代码如下:

from flask import Flask
import os
from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)
t = app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///' + os.path.join(app.root_path, 'data.db'))
db = SQLAlchemy(app)print(t)
print(db)

运行输出:

sqlite:///D:\code_all\gitCode\helloflask_learn\数据库\data.db
<SQLAlchemy>

补充os.getenv是一个Python标准库函数,它用于从环境变量中获取指定的值。这个函数的第一个参数是要查找的环境变量名称,第二个参数是默认值,如果未找到指定的环境变量,则返回这个默认值。

2、定义数据库模型

模型类继承自SQLAlchemy提供的db.Model基类,表的字段由db.Column类的实例表示。

SQLAlchemy常用的字段类型:(p144)

常用的字段参数:(p145)

class Note(db.Model):id = db.Column(db.Integer, primary_key=True)body = db.Column(db.Text)
  • 表名称会根据模型的类名称自动生成,可用__tablename__属性指定。

  • 字段名默认为类属性名,看用name关键字参数指定。

3、创建数据库和表

db.create_all()

可以查看模型对象的建表SQL语句:

from app import Note
from sqlalchemy.schema import CreateTable
print(CreateTable(Note.__table__))

改动模型类后,再次调用create_all()不会更新表结构。可以调用drop_all()方法删除数据库和表,然后重建。

可以自定义一个flaks命令完成数据库的创建工作,对于sqlite创建成功后会生成一个数据库文件,如data.db

import click
@app.cli.command()
def initdb():db.create_all()click.echo('Initialized database')

5.4 数据库操作

SQLAlchemy使用数据库会话(也称为事务)来管理数据库操作,会话代表一个临时存储区,对会话对象调用commit()方法时,改动才被提交到数据库。调用rollback()方法可以撤销会话中未提交的改动。

1、CRUD

即Create、Read、Update、Delete。

  • Create
note = Note(body='hello, world')
db.session.add(note)
db.session.commit()

通过add_all()可以一次提交一个列表。

  • Read
<模型类>.query.<过滤方法>.<查询方法>
Note.query.filter(Note.body=='hello, world').first

Query对象调用过滤方法的返回值仍然是一个Query对象,就像SQL的操作对象和返回结果都是表。查询方法返回的是模型类实例。

常用的SQLAchemy查询方法:(p148) all()first()count()paginate()get(ident)

常用过滤方法:(p150) filter()filter_by()order_by()limit()group_by()

常用查询操作符:(p150) LIKE,IN,NOT IN,AND,OR等。

  • Update
note = Note.query.get(2)
note.body = 'hello, flask'
db.session.commit()
  • Delete
note = Note.query.get(2)
db.session.delete(note)
db.session.commit()

2、在视图函数里操作数据库

与在python shell中基本一致。

5.5 定义关系

1、配置Python Shell上下文

使用app.shell_context_processor装饰器注册一个shell上下文处理函数,返回包含变量和变量值的字典。

@app.shell_context_processor
def make_shell_context():return dict(db=db, Note=Note)

2、一对多关系

定义一对多关系包含两个部分:定义外键,和定义关系属性。其中关系属性相当于一个快捷查询,不会作为字段被写入到数据库中。下面的关系属性articles会返回该作者所有文章的记录列表。

class Author(db.Model):...articles = db.relationship('Article')class Article(db.Model):...author_id = db.Column(db.Integer, db.ForeignKey('athor.id'))

可以在两侧都定义一个关系属性,称为双向关系,需要用到back_populates关键字参数,值为另一侧的关系属性名。

class Author(db.Model):...articles = db.relationship('Article', back_populates='author')class Article(db.Model):...author_id = db.Column(db.Integer, db.ForeignKey('athor.id'))author = db.relationship('Author', back_populates='articles')

可以使用backref简化关系定义,(p163)

疑惑:为什么要手动在两侧都指定反向引用,而不是添加了外键属性之后就自动的呢?是采用了数据库中的索引吗?

定义关系后,建立关系有两种方式,一种是为外键字段赋值,另一种是通过操作关系属性

# 为外键字段赋值
article_A.author_id = 1
# 操作关系属性: append, remove, pop
Mike.articles.append(article_A)

常用关系函数参数:p161

常用关系记录加载方式:p161

3、一对一关系

实际上是在通过建立一对多关系的双向关系的基础上转化而来,只是在原来”一“的一方设置userlist=False,将集合属性变为标量属性。此后,无法再使用列表语义操作,如append方法。

class Contry(db.Model):...capital = db.relationship('Capital', uselist=False)
class Capital(db.Model):...contry_id = db.Column(db.Integer, db.ForeignKey('country.id'))contry = db.relationship('Country')

4、多对多关系

一对多关系中在“多”的一方存放外键,则“多”一方的每条记录只能有一条关系。我们可以单独创建一个关联表(db.Table)来存储外键,表示多对多关系。使用secondary参数来指定关联表。

association_table = db.Table('association',db.Column('student_id', db.Integer, db.ForeignKey('student.id')),db.Column('teacher_id', db.Integer, db.ForeignKey('teacher.id')))class Student(db.Model):...teachers = db.relationship('Teacher', secondary=association_table, back_populates='students')class Teacher(db.Model):...students = db.relationship('Student', secondary=association_table, back_populates='teachers')    

5.6 更新数据库表

1、重新生成表

方法很简单,但缺点是会丢失原来的所有数据

db.drop_all()
db.create_all()

2、使用Flask-Migrate迁移(p169)

可以保留数据库中原有的数据。自动生成的迁移命令不一定可靠,必要时检查一下。

flask db init # 创建迁移环境
flask db migrate # 生成迁移脚本
flask db upgrade # 应用迁移
flask db downgrade # 撤销一次迁移

5.7 数据库进阶

1、级联操作(p172)

relationship方法可以配置cascade参数,所有可用值为save-update,merge,refresh-expire,expunge,delete。默认值为save-update,merge

class Post(db.Model):...comments = db.relationship(..., cascade='save-update, merge, delete')
  • save-updatedb.session.add()将Post对象添加到数据库会话时,相关的Comment对象也会被添加到数据库会话。

  • delete:Post记录被删除时,相关的Comment记录也会被删除。

  • delete-orphan:Post与Comment记录解除关系操作时,相应的Comment记录会被删除。

  • all:包含除了delete-orphan之外的所有可用值。

2、事件监听(p176)

在Flask中有请求回调函数,而SQLAlchemy也提供了listens_for()装饰器来注册事件回调函数。装饰器接受两个参数,target表示监听的对象,identifier表示被监听事件的类型。被注册的监听函数需要接收对应事件方法的所有参数。

疑惑:“事件方法”指什么?怎么知道它有哪些参数?

class Draft(db.Model):...edit_time = ...@db.event.listens_for(Draft.body, 'set', named=True)
def increment_edit_time(**kwargs):if kwargs['target'].edit_time is not None:kwargs['target'].edit_time += 1

设置named参数为True可以使用kwargs接收所有参数(不知道为啥)。kwargs中的target参数表示触发事件的模型类实例


小结

SQLAlchemy入门教程:(p177)http://docs.sqlalchemy.org/en/latest/orm/tutorial.html

数据库这一章我看得有点拖拉,正值开学,可能需要好些天才能找回学习状态。大部分东西我还是之前都有所了解,因此看得比较流畅。在最近开发自己的玩具程序的过程中,数据库这一环节可给我制造了不少麻烦(特别是配环境),它在我眼里的黑盒程度又比较高,书中说到本章只是一个简单的介绍,不过暂时于我也够用了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/126832.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法通关村14关 | 堆在数组中找第k大的元素应用

1. 在数组中找第k大元素 题目 LeetCode215&#xff1a;给定整数数组nums和整数k&#xff0c;请返回数组中第k个最大的元素&#xff0c; 思路 解题思路用三个&#xff0c;选择法&#xff0c;堆查找和快速排序。 我们选择用大堆小堆解决问题&#xff0c;“找最大用小堆&#xff…

【JS面试题】如何通过闭包漏洞在外部修改函数中的变量

✍️ 作者简介: 前端新手学习中。 &#x1f482; 作者主页: 作者主页查看更多前端教学 &#x1f393; 专栏分享&#xff1a;css重难点教学 Node.js教学 从头开始学习 ajax学习 前端面试题 文章目录 什么是闭包例 如何在函数外部修改闭包中变量 什么是闭包 闭包这个东西对新…

animate.css与vue中的v-if/v-show如何一起使用

第一步:在已有的vue项目中安装animate.css npm install animate.css --save第二步&#xff1a;在 main.js 引入 import animate.css第三步&#xff1a;如果在vue中使用了v-if 或者v-show 的话就不能直接在元素上加入animate的class。我们应该在v-if/v-show的元素外层添加tran…

一个新工具 nolyfill

名字的意思&#xff0c; 我自己的理解 no(po)lyfill 正如它的名字, 不要再用补丁了, 当然这里说的是过时的补丁。 polyfill 是补丁的意思 为什么要用这个插件 文档原文: 当您通过安装最新的 Node.js LTS 来接受最新的功能和安全修复时&#xff0c;像eslint-plugin-import、…

基于Java+SpringBoot+Vue前后端分离高校专业实习管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

项目实战:ES的增加数据和查询数据

文章目录 背景在ES中增加数据新建索引删除索引 在ES中查询数据查询数据总数量 项目具体使用&#xff08;实战&#xff09;引入依赖方式一&#xff1a;使用配置类连接对应的es服务器创建配置类编写业务逻辑----根据关键字查询相关的聊天内容在ES中插入数据 总结提升 背景 最近需…

如何建设一个安全运营中心(SOC)?

然信息安全管理问题主要是个从上而下的问题&#xff0c;不能指望通过某一种工具来解决&#xff0c;但良好的安全技术基础架构能有效的推动和保障信息安全管理。随着国内行业IT应用度和信息安全管理水平的不断提高&#xff0c;企业对于安全管理的配套设施如安全运营中心&#xf…

51单片机的简易篮球计分器倒计时仿真设计( proteus仿真+程序+原理图+报告+讲解视频)

51单片机的简易篮球计分器倒计时仿真设计( proteus仿真程序原理图报告讲解视频&#xff09; 1.主要功能&#xff1a;2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&&下载链接 51单片机的简易篮球计分器倒计时仿真设计( proteus仿真程序原理图报告讲解视频…

Go语言中的数组、切片和映射解析

目录 数组数组的声明数组循环 切片切片声明切片元素循环 映射Map的声明及初始化Map的遍历 数组 数组存放的是固定长度、相同类型的数据&#xff0c;而且这些存放的元素是连续的。 数组的声明 例如声明一个整形数组&#xff1a; array : [3]int{1, 2, 3}在类型名前加 [] 中括…

Java序列化与反序列化

Java开发时&#xff0c;有时需要实现序列化和反序列化操作。这里记录下序列化与反序列化的使用总结。 定义 序列化是将Java对象转换为字节序列的过程。在序列化过程中&#xff0c;Java对象被转换为一个字节流。 反序列化是将字节序列转换回Java对象的过程。在反序列化过程中&…

OpenCV(二十九):图像腐蚀

1.图像腐蚀原理 腐蚀操作的原理是将一个结构元素&#xff08;也称为核或模板&#xff09;在图像上滑动&#xff0c;并将其与图像中对应位置的像素进行比较。如果结构元素的所有像素与图像中对应位置的像素都匹配&#xff0c;那么该位置的像素值保持不变。如果结构元素的任何一个…

freemarker模板引擎详解以及使用方法

哈喽&#xff01;大家好&#xff0c;我是旷世奇才李先生 文章持续更新&#xff0c;可以微信搜索【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】更有我为大家准备的福利哟&#xff0c;回复【项目】获取我为大家准备的项目 文章目录 一、freemarker 介绍1、简介 二、free…

Llama 2 论文《Llama 2: Open Foundation and Fine-Tuned Chat Models》阅读笔记

文章目录 Llama 2: Open Foundation and Fine-Tuned Chat Models1.简介2.预训练2.1 预训练数据2.2 训练详情2.3 LLAMA 2 预训练模型评估 3. 微调3.1 supervised Fine-Tuning(SFT)3.2 Reinforcement Learning with Human Feedback (RLHF)3.2.1 人类偏好数据收集3.2.2 奖励模型训…

Excel VSTO开发11-自定义菜单项

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 11 自定义菜单项 自定义菜单项可以在插件启动时候添加&#xff0c;即增加到ThisAddIn_Startup() 内。 下面以具体代码说明&#x…

Mysql锁

文章目录 1. 概述2. 分类3. 全局锁4. 表级锁5. 行级锁 1. 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并…

Leetcode:349. 两个数组的交集【题解超详细】

题目 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 难度&#xff1a;简单 题目链接&#xff1a;349.两个数组的交集 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,…

2023国赛 C题论文 蔬菜类商品自动定价与补货策略

因为一些不可抗力&#xff0c;下面仅展示小部分论文&#xff0c;其余看文末 一、问题重述 在生鲜超市管理领域&#xff0c;涉及一系列复杂问题&#xff0c;包括供应链管理、定价策略以及市场需求分析等方面。以蔬菜类商品为案例&#xff0c;这些商品在生鲜商超中具有较短的保…

开源电商项目 Mall:构建高效电商系统的终极选择

文章目录 Mall 项目概览前台商城系统后台管理系统系统架构图业务架构图 模块介绍后台管理系统 mall-admin商品管理&#xff1a;功能结构图-商品订单管理&#xff1a;功能结构图-订单促销管理&#xff1a;功能结构图-促销内容管理&#xff1a;功能结构图-内容用户管理&#xff1…

python串口采集数据绘制波形图

这个示例使用 matplotlib 绘制图形&#xff0c;它能够从串口实时读取数据并绘制成波形图。确保你已经替换了 ‘COM11’ 和 9600 为正确的串口号和波特率。 import serial import matplotlib.pyplot as plt from collections import deque import struct# 配置串口参数 ser s…

SQL SERVER 如何实现UNDO REDO 和PostgreSQL 有近亲关系吗

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,SQL Server&#xff0c;Redis &#xff0c;Oracle ,Oceanbase 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加微信号 l…