Flask狼书笔记 | 05_数据库

news2024/11/13 8:05:55

请添加图片描述

文章目录

  • 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 SQLAlchemy

app = 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.coloradmin.cn/o/977785.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

02JVM_垃圾回收GC

二、垃圾回收GC 在堆里面存放着java的所有对象实例&#xff0c;当对象为“死去”&#xff0c;也就是不再使用的对象&#xff0c;就会进行垃圾回收GC 1.如何判断对象可以回收 1.1引用计数器 介绍 在对象中添加一个引用计数器&#xff0c;当一个对象被其他变量引用时这个对象…

软件架构之前后端分离架构服务器端高并发演进之路

软件架构之前后端分离架构&服务器端高并发演进之路 前后端分离架构服务器端关于不同并发量的演进之路1. 单体架构2. 第一次演进&#xff1a;应用服务器和数据库服务器分开部署3. 第二次演进&#xff1a;引入本地缓存和分部署缓存4. 第三次演进&#xff1a;引入反向代理和负…

SQL语句如何生成PDM文件

首先我们先了解一下什么是PDM 物理数据模型&#xff08;PDM&#xff09;是数据库设计和管理过程中的重要组成部分&#xff0c;具有以下好处&#xff1a; 可视化数据库结构&#xff1a; PDM提供了一个直观的方式来可视化数据库的结构&#xff0c;包括表、列、索引、关系等。这使…

数据结构与算法学习(day4)——解决实际问题

前言 在本章的学习此前&#xff0c;需要复习前三章的内容&#xff0c;每个算法都动手敲一遍解题。宁愿学慢一点&#xff0c;也要对每个算法掌握基本的理解&#xff01; 前面我们学习了简化版桶排序、冒泡排序和快速排序三种算法&#xff0c;今天我们来实践一下前面的三种算法。…

QT连接OpenCV库完成人脸识别

1.相关的配置 1> 该项目所用环境&#xff1a;qt-opensource-windows-x86-mingw491_opengl-5.4.0 2> 配置opencv库路径&#xff1a; 1、在D盘下创建一个opencv的文件夹&#xff0c;用于存放所需材料 2、在opencv的文件夹下创建一个名为&#xff1a;opencv3.4-qt-intall 文…

Android Glide in RecyclerView,only load visible item when page return,Kotlin

Android Glide in RecyclerView&#xff0c;only load visible item when page return&#xff0c;Kotlin base on this article&#xff1a; Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片&#xff0c;Kotlin_zhangphil的博客…

L1和L2正则

L1和L2正则 L1正则常被用来进行特征选择&#xff0c;主要原因在于L1正则化会使得较多的参数为0&#xff0c;从而产生稀疏解&#xff0c;我们可以将0对应的特征遗弃&#xff0c;进而用来选择特征。一定程度上L1正则也可以防止模型过拟合。 L2正则&#xff1a; L1损失函数相比于…

口袋参谋:淘宝卖家如何对订单实现批量标旗?

​插旗在淘宝店铺里是经常能使用到的&#xff0c;如果淘宝卖家订单量太大&#xff0c;一个一个的标旗太过于繁琐&#xff0c;而且容易出错。 那么使用批量插旗工具&#xff0c;则可以大大节省卖家时间&#xff0c;提高工作效率&#xff01; 【批量插旗】功能&#xff1a; 一键…

基于blockqueue的生产和消费模型

线程篇下讲的是基于阻塞队列的生产者消费者模型。在学习这个之前我们先了解一些其他概念&#xff1a; 同步&#xff1a;在保证数据安全的条件下&#xff0c;让线程按某种特定的顺序依次访问临界资源。 通过上一节的代码我们实现了一个多线程抢票的程序&#xff0c;但结果显示…

Pytorch学习:卷积神经网络—nn.Conv2d、nn.MaxPool2d、nn.ReLU、nn.Linear和nn.Dropout

文章目录 1. torch.nn.Conv2d2. torch.nn.MaxPool2d3. torch.nn.ReLU4. torch.nn.Linear5. torch.nn.Dropout 卷积神经网络详解&#xff1a;csdn链接 其中包括对卷积操作中卷积核的计算、填充、步幅以及最大值池化的操作。 1. torch.nn.Conv2d 对由多个输入平面组成的输入信号…

ChatGPT AIGC 完成超炫酷的大屏可视化

大屏可视化一直各大企业进行数据决策的重要可视化方式,接下来我们先来看一下ChatGPT,AIGC人工智能帮我们实现的综合案例大屏可视化效果: 像这样的大屏可视化使用HTML,JS,Echarts就可以来完成,给ChatGPT,AIGC发送指令的同时可以将数据一起发送给ChatGPT。 第一段指令加数…

Direct3D绘制旋转立方体例程

初始化文件见Direct3D的初始化_direct3dcreate9_寂寂寂寂寂蝶丶的博客-CSDN博客 D3DPractice.cpp #include <windows.h> #include "d3dUtility.h" #include <d3dx9math.h>IDirect3DDevice9* Device NULL; IDirect3DVertexBuffer9* VB NULL; IDirect3…

【C语言】入门——结构体

目录 结构体 为什么有结构体&#xff1f; 1.结构体的声明 1.2结构体变量的访问和初始化 2.结构体成员的访问 结构体 struct 结构体类型 {//相关属性; }结构体变量; 结构体和数组不同&#xff0c;同一类型的数据的集合是数组&#xff1b; 结构体是多种类型的数据的集合&…

NSV60600MZ4T1G 双极型晶体管(BJT)学习总结

双极型晶体管的起源: 双极型晶体管是在1947年发明的&#xff0c;第一个晶体管是将两条具有尖锐端点的金属线与锗衬底(germanium substrate)形成点接触(point contact)&#xff0c;以今天的水准来看&#xff0c;此第一个晶体管虽非常简陋但它却改变了整个电子工业及人类的生活方…

CANdelaStudio CDD编写方法

本文是基于CANdelaStudio12.0讲解 一.把DTC从Excel导入cdd的方法 问题一&#xff1a;当导入DTC的xxx.cdi文件报如下红色错误 可能原因&#xff1a;在设置具有下拉框的属性的内容时&#xff0c;输入的内容不在下拉框列表中 解决办法:在.cddt文件中更新“”Error Code Table“”…

通达信趋向指标DMI公式详解

DMI指标(Directional Movement Index)也称趋向指标或动向指标&#xff0c;是用于衡量市场的趋势方向以及趋势强度的一种技术指标&#xff0c;由著名的技术派大师威尔斯威尔德(Welles Wilder)于1978年发表在《技术交易系统新概念》这本书中。威尔斯威尔德(Welles Wilder)这位大佬…

企微SCRM营销平台MarketGo-ChatGPT助力私域运营

一、前言 ChatGPT是由OpenAI&#xff08;开放人工智能&#xff09;研发的自然语言处理模型&#xff0c;其全称为"Conversational Generative Pre-trained Transformer"&#xff0c;即对话式预训练转换器。它是GPT系列模型的最新版本&#xff0c;GPT全称为"Gene…

springboot项目中application.properties无法变成小树叶问题解决

1.检查我们的resources目录的状态&#xff0c;看看是不是处在普通文件夹的状态&#xff0c;如果是的话&#xff0c;我们需要重新mark一下 右键点击文件夹&#xff0c;选择mark directory as → resources root 此时我们发现配置文件变成了小树叶 2.如果执行了上述方法还是不行…

[uniapp]踩坑日记 unexpected character > 1或‘=’>1 报错

在红色报错文档里下滑&#xff0c;找到Show more 根据提示看是缺少标签&#xff0c;如果不是缺少标签&#xff0c;看看view标签内容是否含有<、>、>、<号,把以上符合都进行以<号为例做{{“<”}}处理

超详细-Vivado配置Sublime+Sublime实现VHDL语法实时检查

目录 一、前言 二、准备工作 三、Vivado配置Sublime 3.1 Vivado配置Sublime 3.2 环境变量添加 3.3 环境变量验证 3.4 Vivado设置 3.5 配置验证 3.6 解决Vivado配置失败问题 四、Sublime配置 4.1 Sublime安装Package Control 4.2 Sublime安装VHDL插件 4.3 语法检查…