Python Flask框架(五)数据库

数据库是大多数动态Web程序的基础设施,本章主要介绍如何给Flask程序添加数据库支持,具体来说就是在Python中使用DBMS来对数据库进行管理和操作。

使用ORM不光可以解决SQL注入的问题,而且它为不同的DBMS提供统一的Python接口库,使得切换数据库非常简单。ORM把底层的SQL数据实体转化成高层的Python对象,这样甚至不用了解SQL,只需要通过Python代码即可完成数据库操作,ORM主要实现了三层映射关系:

  • 表 --> Python类
  • 字段(列) --> 类属性
  • 记录(行) --> 类实例

SQLAlchemy是python社区使用最广泛的ORM之一,Flask-SQLAlchemy库集成了SQLAlchemy。要连接数据库服务器,首先要为我们的程序指定数据库URI。数据库的URI配置变量SQLALCHEMY_DATABASE_URI设置。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
db = SQLAlchemy(app)app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', prefix + os.path.join(app.root_path, 'data.db'))

用来映射到数据库表的Python类被称为数据库模型,一个数据库模型类对应数据库中的一个表。所有模型类都需要继承Flask-SQLAlchemy提供的db.Model基类。

# Models
class Note(db.Model):id = db.Column(db.Integer, primary_key=True)body = db.Column(db.Text)

默认情况下,Flask-SQLAlchemy会根据模型类的名称生成一个表名称,类名称是单个单词时,就转换为小写,如果类名称是多个单词,就转化小写后用下划线分割。

在实例化字段时,通过把参数primary_key设为True可以将其定义为主键。主键是每一条记录(行)独一无二的标识,也是模型类中必须定义的字段。

数据库的CRUD

1、create

添加一条新记录到数据库主要分三步:
1)创建Python对象(实例化模型类)作为一条记录
2)添加新创建的记录到数据库会话
3)提交数据库会话

note1 = Note(body='hello world')
db.session.add(note1)
db.session.commit()

id字段的数据没有定义是因为主键由SQLAlchemy管理,当提交数据库会话后,会自动获得id值。

2、read

一般来说,一个完整的查询遵循下面的模式:
<模型类>.query.<过滤方法>.<查询方法>

常用的SQLAlchemy查询方法

查询方法说明
all()返回包含所有查询记录的列表
first()返回查询的第一条记录,如果未找到,则返回None
one()返回第一条记录,且仅允许有一条记录。若果记录数量大于等于1则报错
get(id)传入主键作为参数,返回指定主键值的记录
count()返回查询结果数量
one_or_none()类似one(),如果数量不为1,返回None
first_or_404()返回查询的第一条记录,如果未找到,返回404错误
get_or_404(id)传入主键作为参数,返回指定主键值的记录,未找到报404错误

常用的SQLAlchemy过滤方法

过滤方法说明
filter()使用指定的规则记录,返回新产生的查询对象
filter_by()使用指定规则过滤记录(直接使用字段名称),返回新产生的查询对象
order_by()根据指定条件对记录进行排序,返回新产生的查询对象
limit(limit)使用指定的值限制原查询返回的记录数量,返回新产生的查询对象
group_by()根据指定条件对记录进行分组,返回新产生的查询对象
offset(offset)使用指定的值偏移原查询结果,返回新产生的查询对象

在filter()中除了"==“和”!="其他操作符如下:

  • LIKE:
filetr(Note.body.like('%foo%'))
  • IN:
filetr(Note.body.in_(['foo','bar','baz']))
  • NOT IN:
filetr(~Note.body.in_(['foo','bar','baz']))
  • AND:
filetr(and_(Note.body=='foo%',Note.title=='Foobar'))
  • OR:
filetr(or_(Note.body=='foo%',Note.body=='bar'))
3、update

更新记录非常简单,直接赋值给模型类的字段属性就可以改变字段值,然后调用commit()方法提交即可。

note1.body = 'ni hao'
db.session.commit()
4、delete

删除记录和添加记录很类似,不过要把add换成delete,最后需要commit提交修改。

db.session.delete(note1)
db.session.commit()

定义关系

在关系型数据库中,我们可以通过关系让不同表之间的字段建立联系。一般来说,定义关系需要两步,分别是创建外键和定义关系属性。

例如作者和文章是一对多关系:

class Author(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(20), unique=True)phone = db.Column(db.String(20))articles = db.relationship('Article')  # collectionclass Article(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(50), index=True)body = db.Column(db.Text)author_id = db.Column(db.Integer, db.ForeignKey('author.id'))
1、 一对多

定义关系的第一步是创建外键,外键是用来在A表存储B表的主键值以便和B表建立联系的关系字段。因为外键只能存储单一数据,所以外键总是在“多”这一侧定义。所以上述示例中我们需要为每篇文章添加外键存储作者的主键值以指向对应的作者。

class Article(db.Model):...author_id = db.Column(db.Integer, db.ForeignKey('author.id'))	

在Article模型中,我们定义一个autho_id字段作为外键。这个字段使用db.ForeignKey类定义外键,传入关系另一侧的表名和主键字段名,即author.id。

定义关系的第二步是使用关系函数定义关系属性。关系属性在关系的出发侧定义,即一对多关系的“一”这一侧。在Author模型中,我们定义了一个articles属性来表示对应的多篇文章:

class Author(db.Model):...articles = db.relationship('Article') 

relationship函数的第一个参数为关系另一侧的模型名称,它会告诉SQLAlchemy将Author类与Article类建立关系。当这个关系属性被调用时,SQLAlchemy会找到关系另一侧(即article表)的外键字段(即author_id)然后反向查询article表中所有author_id值为当前表主键值(即author.id)的记录,返回包含这些记录的列表,也就是返回某个作者对应的多篇文章记录。

关系属性定义完,下面我们为实际的对象建立关系。
首先建立一个作者记录和两个文章记录:

foo = Author(name='Foo')
spam = Article(title='Spam')
ham = Article(title='Ham')

建立关系,可以像列表一样操作,调用append方法来与一个article对象建立联系。

foo.article.append(spam)
foo.article.append(ham)
db.session.commit()

以上关系是单向的,还可以创建双向关系,也就是说在作者和文章类中都创建一个relationship函数,就可以在两个表间建立双向关系。

class Writer(db.Model):...books = db.relationship('Book',back_populates='writer')class Book(db.Model):...writer = db.relationship('Writer',back_populates='books')

在关系函数中,我们使用back_populates参数来连接对方,back_populates参数的值需要设为关系另一侧的关系属性名。或者使用backref简化关系定义,backref参数用来自动为关系另一侧添加关系属性,作为反向引用。这时我们只需定义一个关系函数,但在使用上和上面定义两个关系函数效果完全相同。

class Writer(db.Model):...books = db.relationship('Book',backref='writer')class Book(db.Model):...
2、 多对一

例如居民和城市的关系,前面说过关系属性在关系模式的出发侧定义,外键在“多”这一侧定义,所以在多对一关系中外键和关系属性都定义在“多”这一侧。

class Citizen(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(70), unique=True)city_id = db.Column(db.Integer, db.ForeignKey('city.id'))city = db.relationship('City')  class City(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(30), unique=True)
3、一对一

一对一关系实际上是通过建立双向关系的一对多关系的基础上转化来的。我们要确保关系两侧的关系属性都只返回单个值,所以要在定义集合属性的关系函数中将uselist参数设为false,这时一对多关系将被转化为一对一关系。以国家和首都为例。

class Country(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(30), unique=True)capital = db.relationship('Capital', back_populates='country', uselist=False)  class Capital(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(30), unique=True)country_id = db.Column(db.Integer, db.ForeignKey('country.id'))country = db.relationship('Country', back_populates='capital')  
4、多对多

多对多关系中,关系两侧的模型都需要存储一组外键,因此我们创建一个关联表,关联表不存储数据,只用来存储关系两侧模型的外键对应关系。我们以老师和学生为例。

关联表使用db.Table类定义,传入的第一个参数是关联表名称。

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):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(70), unique=True)grade = db.Column(db.String(20))teachers = db.relationship('Teacher',secondary=association_table,back_populates='students')  # collectionclass Teacher(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(70), unique=True)office = db.Column(db.String(20))students = db.relationship('Student',secondary=association_table,back_populates='teachers')  # collection

借助关联表这个存储外键对的中间表,我们可以把多对多关系分化成两个一对多关系,即老师表和学生表相对于关联表都是一对多关系。

更新数据库表

模型类(表)不是一成不变的,当添加了新的模型类,或是在模型类中添加了新的字段,甚至是修改了字段的名称或类型,都需要更新表。数据库表并不会随着模型的修改而自动更新。

最简单的方式就是删除所有表以及表中的数据,然后使用create_all()重新创建。但这种方式有很大的局限性,我们还可以借助数据库迁移工具(flask-migrate)来完成这个工作。数据库迁移工具可以在不破坏数据的情况下,更新数据库表的结构。

首先实例化Migrate类

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrateapp = Flask(__name__)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
1、创建迁移环境
$ flask db init

迁移环境只需要创建一次,这会在项目根目录下创建一个migrations文件夹,其中自动包含了自动生成的配置文件和迁移版本文件夹。

2、生成迁移脚本

使用migrate子命令可以自动生成迁移脚本

$ flask db migrate -m "add note timestamp"

-m 选项用来添加迁移备注信息。

3、更新数据库

生成迁移脚本后,使用upgrade子命令即可更新数据库

$ flask db upgrade

参考资料:《Flask Web开发实战入门、进阶与原理解析》李辉 著

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

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

相关文章

芝浦工业大学利用 NetApp 提供的多层 AI 驱动型安全解决方案抵御网络攻击

成效 10,000 名学生和教职工受到现代存储基础架构的保护NetApp AI 技术可自动检测异常并即时创建数据备份借助 NetApp 重复数据删除和数据压缩将数据缩减了 60% NETAPP 打造现代化的数据保护 众所周知&#xff0c;教育机构很难防范网络攻击。学生、员工和教职工都需要使用自己…

全面解析API网关:动态路由、协议转换及安全防护策略

1.API网关简介与架构演进 1.1. 什么是API网关 API 网关是一种服务器&#xff0c;是多个客户端应用程序至后端服务数据流的中间层。它作为单一的接入点&#xff0c;处理所有应用程序之间的请求通信。API 网关的主要功能包括请求路由、API 组合、策略执行和转换请求和响应。 1…

Web程序设计-实验05 DOM与BOM编程

题目 【实验主题】 影视网站后台影视记录管理页设计 【实验任务】 1、浏览并分析多个网站后台的列表页面、编辑页面&#xff08;详见参考资源&#xff0c;建议自行搜索更多后台页面&#xff09;的主要元素构成和版面设计&#xff0c;借鉴并构思预期效果。 2、新建 index.h…

正则匹配优化:匹配排除多个字符串的其他字符串

(^entity|^with|...)\w优化 (?!entity|with|has|index|associations|input)\w(?!): 匹配排除项 效果 继续优化 匹配会过滤掉带有关键字的字段&#xff0c;在过滤的时候是可以加上尾部结束匹配符的 效果&#xff1a;

thinkphp6 自定义的查询构造器类

前景需求&#xff1a;在查询的 时候我们经常会有一些通用的&#xff0c;查询条件&#xff0c;但是又不想每次都填写一遍条件&#xff0c;这个时候就需要重写查询类&#xff08;Query&#xff09; 我目前使用的thinkphp版本是6.1 首先自定义CustomQuery类继承于Query <?p…

【C语言回顾】预处理

前言1. 简单概要2. 预处理命令讲解结语 上期回顾: 【C语言回顾】编译和链接 个人主页&#xff1a;C_GUIQU 归属专栏&#xff1a;【C语言学习】 前言 各位小伙伴大家好&#xff01;上期小编给大家讲解了C语言中的编译和链接&#xff0c;接下来我们讲解一下预处理&#xff01; …

【香橙派 AIpro】新手保姆级开箱教程:Linux镜像+vscode远程连接

香橙派 AIpro 开发板 AI 应用部署测评 写在最前面一、开发板概述官方资料试用印象适用场景 二、详细开发前准备步骤1. 环境准备2. 环境搭建3. vscode安装ssh插件4. 香橙派 AIpro 添加连接配置5. 连接香橙派 AIpro6. SSH配置 二、详细开发步骤1. 登录 juypter lab2. 样例运行3. …

MySQL主从搭建--保姆级教学

MYSQL主从搭建步骤 主节点 # 进入目录 cd /opt# 下载安装包 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz# 解压 tar -xvf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz# 拷贝到/usr/local mv /opt/mysql-8.0.20-linux-g…

【IDEA】-使用IDEA查看类之间的依赖关系

1、父子类的继承、实现关系 1.1、使用CTRL Alt U 选择 java class 依据光标实际指向的类位置 用实心箭头表示泛化关系 是一种继承的关系&#xff0c;指向父类 可以提前设置需要显示的类的属性、方法等信息 快捷键 Ctrl Alt S &#xff0c;然后搜索 Diagrams 1.2、使用…

python知识继续学习

1、计算机表示小数是有误差的&#xff0c;下面的5就是误差 2、在python中&#xff0c;所有的非0数字都是True&#xff0c;零是False。所有的非空字符串都是True&#xff0c;空字符串是False。空列表是False。在python的基本数据类型中&#xff0c;表示空的东西都是False&#x…

数据结构(三)循环链表 约瑟夫环

文章目录 一、循环链表&#xff08;一&#xff09;概念&#xff08;二&#xff09;示意图&#xff08;三&#xff09;操作1. 创建循环链表&#xff08;1&#xff09;函数声明&#xff08;2&#xff09;注意点&#xff08;3&#xff09;代码实现 2. 插入&#xff08;头插&#x…

【linux】运维-基础知识-认知hahoop周边

1. HDFS HDFS&#xff08;Hadoop Distributed File System&#xff09;–Hadoop分布式文件存储系统 源自于Google的GFS论文&#xff0c;HDFS是GFS的克隆版 HDFS是Hadoop中数据存储和管理的基础 他是一个高容错的系统&#xff0c;能够自动解决硬件故障&#xff0c;eg&#xff1a…

【Linux 网络编程】网络的背景、协议的分层知识!

文章目录 1. 计算机网络背景2. 认识 "协议"3. 协议分层 1. 计算机网络背景 网络互联: 多台计算机连接在一起, 完成数据共享; &#x1f34e;局域网&#xff08;LAN----Local Area Network&#xff09;: 计算机数量更多了, 通过交换机和路由器连接。 &#x1f34e; 广…

多模态模型入门:BLIP与OWL-ViT

BLIP 数据预处理 CapFilt&#xff1a;标题和过滤 由于多模态模型需要大量数据集&#xff0c;因此通常必须使用图像和替代文本 (alt-text) 对从互联网上抓取这些数据集。然而&#xff0c;替代文本通常不能准确描述图像的视觉内容&#xff0c;使其成为噪声信号&#xff0c;对于…

MAC M1 —— Install

文章目录 MAC M1 —— Install安装IDEA安装JDK安装Maven安装brew无法创建文件 /data/serverMac 修改终端用户名&#xff08;主机名&#xff09;PyCharm MAC M1 —— Install 安装IDEA 关键词&#xff1a;2020到2021.3的激活步骤。找下Download文件夹 安装JDK 在个人的电脑上…

思维+滑动窗口,LeetCode 2831. 找出最长等值子数组

目录 一、题目 1、题目描述 2、接口描述 python3 cpp JS 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 python3 cpp JS 一、题目 1、题目描述 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 如果子数组中所有元素都相等&#xff0c;则认…

TypeScript 学习笔记(十一):TypeScript 与微服务架构的结合应用

TypeScript 学习笔记(十一):TypeScript 与微服务架构的结合应用 1. 引言 在前几篇学习笔记中,我们探讨了 TypeScript 的基础知识、前后端框架的结合应用、测试与调试技巧、数据库以及 GraphQL 的结合应用。本篇将重点介绍 TypeScript 与微服务架构的结合应用,包括如何使…

mysql数据库管理-mysqlbinlog备份与恢复,主备复制分析

由于服务器生成的二进制日志文件以二进制格式保存&#xff0c;所以如果想要检查这些文件的文本格式&#xff0c; 就会用到mysqlbinlog日志管理工具。 mysqlbinlog的具体用法如下&#xff1a; shell> mysqlbinlog [options] log-files1 log-files2. . option有很多选项&…

《探索Stable Diffusion:AI绘画的创意之路与实战秘籍》

《Stable Diffusion AI 绘画从提示词到模型出图》介绍了 Stable Diffusion AI 绘画工具及其使用技巧。书中内容分为两部分&#xff1a;“基础操作篇”&#xff0c;讲解了 SD 文生图、图生图、提示词、模型、ControlNet 插件等核心技术的应用&#xff0c;帮助读者快速从新手成长…

mysql仿照find_in_set写了一个replace_in_set函数,英文逗号拼接字符串指定替换

开发中使用mysql5.7版本数据库&#xff0c;对于英文逗号拼接的字符串&#xff0c;想要替换其中指定的字符串&#xff0c;找不到数据库函数支持&#xff0c;自己写了一个&#xff0c;实测好用&#xff01; /*类似find_in_set,按英文逗号拆分字段,找出指定的旧字符串,替换成新字…