Flask使用Flask-SQLAlchemy对数据库操作详解一(配置、表与表之间一对一、多对一、多对多关系及增删改查参数和代码详细总结)

news2024/11/24 16:44:04

在这里插入图片描述

文章目录

  • 1.先来一个简单的示例
    • 2.SQLAlchemy 配置(所有的配置都在Flask初始化应用程序之前就执行了)
  • 3.声明模型
    • 3.1声明模型参数
    • 3.2表与表之间的关系(详细介绍)
      • 1.一对一关系
      • 2.多对一关系
      • 3.多对多关系

1.先来一个简单的示例

from flask import Flask
#安装:pip install Flask-SQLAlchemy
from flask_sqlalchemy import SQLAlchemy

#声明一个User模型
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)#主键
    username = db.Column(db.String, unique=True, nullable=False)#username不重复,不可为空
    email = db.Column(db.String)

# 实例化一个SQLAlchemy对象
db = SQLAlchemy()
# 实例化一个Flask对象
app = Flask(__name__)
# SQLite数据库参数
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"

# db.create_all()会创建所有的表,如果表已经在数据库中,则不会更新表,db.drop_all()删除所有表
with app.app_context():
	# 初始化数据库
	db.init_app(app)
    #db.drop_all() #删除所有的表
    db.create_all() #创建所有的表

#下面创建四个路由视图来使用数据库,完成增删改查操作
#查看
@app.route("/users")
def user_list():
    users = db.session.execute(db.select(User).order_by(User.username)).scalars()
    return render_template("user/list.html", users=users)
@app.route("/user/<int:id>")
def user_detail(id):
    user = db.get_or_404(User, id)
    return render_template("user/detail.html", user=user)

#增加
@app.route("/users/create", methods=["GET", "POST"])
def user_create():
    if request.method == "POST":
        user = User(
            username=request.form["username"],
            email=request.form["email"],
        )
        db.session.add(user)
        db.session.commit()
        return redirect(url_for("user_detail", id=user.id))
    return render_template("user/create.html")

#删除
@app.route("/user/<int:id>/delete", methods=["GET", "POST"])
def user_delete(id):
    user = db.get_or_404(User, id)
    if request.method == "POST":
        db.session.delete(user)
        db.session.commit()
        return redirect(url_for("user_list"))
    return render_template("user/delete.html", user=user)

文末有两个我之前练习的示例,均在GitHub上可以自己下载下来运行。

2.SQLAlchemy 配置(所有的配置都在Flask初始化应用程序之前就执行了)

#可以直接放置在Flask配置文件中
#<协议名称>://<⽤户名>:<密码>@<ip地址>:<端⼝>/<数据库名>
#如果使⽤的是mysqldb驱动,协议名: mysql
#如果使⽤的是pymysql驱动,协议名: mysql+pymysql

SQLALCHEMY_DATABASE_URI = "mysql+pymysql://{username}:{password}@{ip_address}:{port}/{database}"

# SQLite, #相对于 Flask 实例路径
SQLALCHEMY_DATABASE_URI = "sqlite:///project.db"

SQLALCHEMY_ECHO = True # 如果设置为True,SQLALchemy会记录所有发给stderr的语句,这对调试有用(会打印sql语句)

SQLALCHEMY_POOL_SIZE #数据库链接池的大小。默认时引擎默认值(通常是5)
SQLALCHEMY_POOL_TIMEOUT#设定链接池的连接超时时间,默认是10
SQLALCHEMY_POOL_RECYCLE #多少秒自动回连连接。对MYsql是必要的。它默认移除闲置多余8小时的连接,注意如果使用了MYSQL, Flask-SQLALchemy自动设定这个值为2小时

3.声明模型

在Flask-SQLAlchemy中,使用模型来表示数据库中的表结构,这些模型通过继承SQLAlchemy中的Base类来创建。下面对Flask-SQLAlchemy定义模型的语法和参数进行总结。

image-20230503222702702

3.1声明模型参数

声明模型示例:

定义了一个名为User的表,它有三个字段:idusernameemail。其中id为主键,usernameemail都是不允许为空且唯一的字符串类型。__repr__方法用于打印对象时显示对象的属性值。

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

在定义模型时,需要选择合适的列类型来存储不同类型的数据。Flask-SQLAlchemy支持多种列类型,下面对其中常用的列类型进行总结:

类型名Python类型说明
Integerint普通整数,一般是 32 位
SmallIntegerint取值范围小的整数,一般是 16 位
Big Integerint 或 long不限制精度的整数
Floatfloat浮点数
Numericdecimal.Decimal定点数
Stringstr变长字符串(其参数有:length:最大长度、nullable:是否允许为空、default:默认值)
Textstr变长字符串,对较长或不限长度的字符串做了优化
Unicodeunicode变长 Unicode 字符串
Unicode Textunicode变长 Unicode 字符串,对较长或不限长度的字符串做了优化
Booleanbool布尔值
Datedatetime.date日期
Timedatetime.time时间
DateTimedatetime.datetime日期和时间
Intervaldatetime.timedelta时间间隔
Enumstr一组字符串
PickleType任何 Python 对象自动使用 Pickle 序列化
LargeBinarystr二进制文件

定义模型时,列类型的参数可以用来指定列的属性。下面对常用的列类型参数进行总结:

选项名说明
primary_keyprimary_key用来指定该列为主键,若一个表中没有主键,则无法使用ORM进行操作。
uniqueunique用来指定该列的值是否唯一,若设置为True,则该列的值必须在表中唯一。
indexindex用来指定该列是否需要索引。若设置为True,则该列可以被用来进行查询,加快查询速度。
nullablenullable用来指定该列的值是否允许为空,若设置为True,则该列的值可以为None
defaultdefault用来指定该列的默认值,若该列的值未设置,则使用该默认值。
autoincrementautoincrement用来指定该列是否自动增加。若设置为True,则每次插入新记录时该列的值会自动增加。

3.2表与表之间的关系(详细介绍)

在 Flask-SQLAlchemy 中,模型是用来表示数据库中表的类,而模型之间的关系是用来表示表之间的关系。下面介绍 Flask-SQLAlchemy 中声明模型间一对一、多对一和多对多关系的语法和方法。

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

  • 外键 db.ForeignKey():定义关系的第一步是创建外键。外键(foreign key)用来在A表存储B表的主键值,以便和B表建立联系的关联字段。因为外键只能存储单一数据(标量),所以外键总是在“多”这一侧定义,多篇文章属于同一个作者,所以我们需要为每篇文章添加外键存储作者的主键值以指向对应的作者。因此外键是用来在两个表之间建立关联的一种机制,db.ForeignKey 函数的参数为关联的模型名称和模型中的字段名称。例如,上面有两个模型 OrderCustomer,可以使用外键将它们关联起来。

    img

  • backref:backref 是用来在两个模型之间建立双向关联的一种机制,上面两个模型 OrderCustomer,我们可以使用 backref 参数来声明 Customer 模型中的 orders 属性,这样就可以通过 customer.orders 来访问该客户的订单列表。

  • db.Table():db.Table 是用来声明多对多关系中的中间表的一种机制。

  • secondary:用来声明多对多关系中的中间表的一种机制。上面使用 secondary 参数来指定中间表的名称 book_author

1.一对一关系

一对一关系表示两个模型之间存在一个唯一的对应关系。在 Flask-SQLAlchemy 中,可以使用 relationship 函数来声明一对一关系。例如,如果有两个模型 UserAddress,其中一个用户只有一个地址,可以这样声明一对一关系:

  • model.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):
    __tablename__="user"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    address = db.relationship('Address', backref='user',uselist=False)

class Address(db.Model):
    __tablename__="address"
    id = db.Column(db.Integer, primary_key=True)
    street = db.Column(db.String(50))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
  • app.py
from flask import Flask
from model import *

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:123456@{ipaddress}:{port}/{database}".format( ipaddress="",port="3306",database="sql_test")
app.config["SQLALCHEMY_ECHO"]= True
app.config["SECRET_KEY"]= 'dsjjkhkhjsdkjchkj'

# 初始化数据库
with app.app_context():
    db.init_app(app)
    db.drop_all()
    db.create_all()
#测试    
@app.route('/')
def hello_world():  # put application's code here
    u1 = User(name="yiyi")
    add1 = Address(street="street1")
    u1.address = add1
    db.session.add_all([u1])
    db.session.commit()
    add2 = Address(street="street2")
    #u1.address.append(ad1) #会报错
    db.session.commit()
    u1name =  add1.user.name
    print("-------------")
    print(u1name) #yiyi
    counts = u1.address
    print(counts.street) #street1
    #换一个地址
    u1.address = add2
    counts = u1.address
    db.session.commit()
    print(counts.street) #street2
    return "成功"
    
if __name__ == '__main__':
    app.run(debug=True)

在上面的代码中:

  • relationship 函数来声明 UserAddress 之间的关系。

  • backref 参数表示在 Address 模型中添加一个名为 user 的属性,该属性引用 User 模型。

  • uselist 参数设置为 False,表示 UserAddress 之间的关系是一对一的关系。

“多”这一侧本身就是标量关系属性,不用做任何的改动(有外键的是“多”这一侧),而“一”这一侧的集合关系属性,通过将uselist参数设置为False后,将近返回对应的单个记录,而且无法再使用列表语义操作,Address.user.append(‘小明’)就会报错。

2.多对一关系

多对一关系表示一个模型可以对应多个另一个模型,而另一个模型只能对应一个该模型。例如,如果有两个模型 OrderCustomer,一个订单只能有一个客户,而一个客户可以有多个订单,可以这样声明多对一关系:

  • model.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Order(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    order_number = db.Column(db.String(50))
    #每一个订单都对应了一个用户
    user_id = db.Column(db.Integer, db.ForeignKey('customer.id'))
    def __repr__(self):
        return '<Order id:%r, order_number:%r>' % (self.id, self.order_number)

class Customer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    orders = db.relationship('Order', backref='customer')
    def __repr__(self):
        return '<Customer id:%r, name:%r>' % (self.id, self.name)
  • app.py
from flask import Flask
from model import *

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:123456@{ipaddress}:{port}/{database}".format( ipaddress="",port="3306",database="sql_test")
app.config["SQLALCHEMY_ECHO"]= True
app.config["SECRET_KEY"]= 'dsjjkhkhjsdkjchkj'

# 初始化数据库
with app.app_context():
    db.init_app(app)
    db.drop_all()
    db.create_all()
#测试
@app.route('/')
def hello_world():  # put application's code here
    u1 = Customer(name="yiyi")
    add1 = Order(order_number="order1")
    add2 = Order(order_number="order2")
    add3= Order(order_number="order3")
    u1.orders.append(add1)
    u1.orders.append(add2)
    db.session.add_all([u1,add2,add1,add3])
    db.session.commit()
    u1name =  add1.customer.name
    print("-------------")
    print(u1name) #yiyi
    counts = u1.orders
    print("-------------")
    print(counts) #[<Order id:7, order_number:'order1'>, <Order id:8, order_number:'order2'>]
    #移除一个订单
    u1.orders.remove(add2)
    counts = u1.orders
    db.session.commit()
    print("-------------")
    print(counts) #[<Order id:1, order_number:'order1'>]
    return "成功"
    
if __name__ == '__main__':
    app.run(debug=True)

在上面的代码中:

  • relationship 函数来声明 OrderCustomer 之间的关系。

  • backref 参数表示在 Customer 模型中添加一个名为 orders 的属性,该属性引用 Order 模型。

  • customer_id 字段是一个外键,用于将 Order 模型与 Customer 模型关联起来。

3.多对多关系

多对多关系表示两个模型之间存在多个对应关系。

在这里插入图片描述

例如,如果有两个模型 BookAuthor,一个作者可以写多本书,一本书可以有多个作者,可以这样声明多对多关系:

  • model.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

book_author = db.Table('book_author',
    db.Column('book_id', db.Integer, db.ForeignKey('book.id')),
    db.Column('author_id', db.Integer, db.ForeignKey('author.id'))
)

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50))
    authors = db.relationship('Author', secondary=book_author, backref='books')

class Author(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
  • app.py
from flask import Flask
from model import *

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:123456@{ipaddress}:{port}/{database}".format( ipaddress="",port="3306",database="sql_test")
app.config["SQLALCHEMY_ECHO"]= True
app.config["SECRET_KEY"]= 'dsjjkhkhjsdkjchkj'

# 初始化数据库
with app.app_context():
    db.init_app(app)
    db.drop_all()
    db.create_all()

#测试
@app.route('/')
def hello_world():
    B1 = Book(title="yiyi")
    B2 = Book(title="eiei")
    B3 = Book(title="sisi")
    A1 = Author(name="Author1")
    A2 = Author(name="Author2")
    A3= Author(name="Author3")
    db.session.add_all([B1,B2,B3,A1,A2,A3])
    db.session.commit()

    B1.authors.append(A1)
    B1.authors.append(A2)

    A3.books.append(B1)
    A3.books.append(B2)

    db.session.commit()
    print("-------------")
    print(B1.authors) #yiyi
    print(A3.books)
    print("-------------")
    
    #输出
    #-------------
    # [<Author 1>, <Author 2>, <Author 3>]
    # [<Book 1>, <Book 2>]
    # -------------  
    return "成功"

if __name__ == '__main__':
    app.run(debug=True)

在上面的代码中:

  • relationship 函数和一个名为 book_author 的中间表来声明 BookAuthor 之间的多对多关系。
  • secondary 参数指定了中间表的名称
  • backref 参数表示在 Author 模型中添加一个名为 books 的属性,该属性引用 Book 模型。
  • 在关联表中,分别指定了 book_idauthor_id 字段作为外键,用于将 Book 模型和 Author 模型关联起来。这样就可以在 Book 模型中声明 authors 属性时直接使用 secondary='book_author' 来引用中间关联表。

Github练习示例:
https://blog.csdn.net/QH2107/article/details/130381365?spm=1001.2014.3001.5502
https://github.com/QHCV/Flask_Book_Manage
参考资料:
https://blog.csdn.net/kongsuhongbaby/article/details/102942673
官方文档:
中文:http://www.pythondoc.com/flask-sqlalchemy/index.html
英文:https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

水平有限,如果有错误或者建议,可以在评论区交流一下。

希望有所帮助!喜欢就点个赞吧!

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

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

相关文章

【Unity3D小功能】Unity3D中实现轮船在水面上移动效果

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 标题是啥我写啥&#xff0c;大家好&#xff0c;今天给大家带来…

chatgpt帮我写的一个小程序气泡框代码

效果图 这是一个气泡框 .bubble { position: relative; padding: 10px; border-radius: 8px; background-color: #ddd; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } .triangle { position: absolute; width: 0; height: 0; top: -10px; left: 50%; margin-left: -10px; bor…

vue集成animate.css

vue集成animate.css 一 <transition> 标签的用法二 关于animate.css三 vue集成animate.css使用 一 <transition> 标签的用法 使用<transition></transition>标签包裹要加动画的元素。 标签中添加属性name&#xff0c;表示执行动画的名字&#xff0c;不…

python 网络接口测试(post)

代码&#xff1a; import requests url https://xxx.com/xxx # 注意这里必须以json字符串构造数据 data { "username": "showdoc", "password": "xxx" } headers {content-type: application/json} # 与 get 请求一样…

STC15W104 定时器实现灯的闪烁(定时器原理讲解)

一&#xff1a;STC15W104单片机有几个定时器 STC15W104单片机共有2个定时器&#xff0c;分别为定时器0、定时器2。 二&#xff1a;定时器的作用 定时器是单片机中的一种常用外设&#xff0c;用于在一定时间间隔内产生中断。 定时器通常用于计时、测量时间间隔、生成PWM信号等应…

【MybatisPlus】高级版可视化、可配置 自动生成代码

今天看别人使用了一个更加智能的生成代码工具&#xff0c;可视化、可配置策略&#xff0c;非常方便&#xff0c;配置一次&#xff0c;在哪都可以使用&#xff0c;也不会跟项目藕合下面简单说一下使用方式。 1、介绍mybatis-plus-generator-ui 主要是封装了mybatis-plus-gener…

【深度学习】计算机视觉(13)——模型评价及结果记录

1 Tensorboard怎么解读&#xff1f; 因为意识到tensorboard的使用远不止画个图放个图片那么简单&#xff0c;所以这里总结一些关键知识的笔记。由于时间问题&#xff0c;我先学习目前使用最多的功能&#xff0c;大部分源码都包含summary的具体使用&#xff0c;基本不需要自己修…

【AWS入门】将EC2的系统日志推送到CloudWatch

创建一个 EC2 实例&#xff0c;不附加任何 IAM profile. ※这里注意不要用23年最新版本的镜像&#xff0c;该镜像不支持awslogs 选择旧版镜像可成功安装awslogs 开始创建一个 IAM profile 创建角色&#xff0c;服务选择 EC2, policy 选择 CloudWatchAgentServerPolicy. 切换回…

GPT 学术优化 (ChatGPT Academic)搭建过程(含ChatGLM cuda INT4量化环境和newbing cookie)

文章目录 1、GPT Academic2、chatGPT3、chatGLM4、newbing 1、GPT Academic 项目地址&#xff1a;地址 安装部分 git clone https://github.com/binary-husky/chatgpt_academic.git cd chatgpt_academicconda create -n gptac_venv python3.11 conda activate gptac_venv pyt…

ASEMI代理ADM3202ARUZ-REEL7原装ADI车规级ADM3202ARUZ-REEL7

编辑&#xff1a;ll ASEMI代理ADM3202ARUZ-REEL7原装ADI车规级ADM3202ARUZ-REEL7 型号&#xff1a;ADM3202ARUZ-REEL7 品牌&#xff1a;ADI /亚德诺 封装&#xff1a;TSSOP-16 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;16 工作温度: …

助力数字轻工发展,企企通亮相第十三届中国轻工业信息化大会

新一代数字技术蓬勃发展&#xff0c;数字经济和实体经济加速融合&#xff0c;数字化不仅仅是生产和管理方式的转变&#xff0c;更是一场创新的革命&#xff0c;只有通过持续创新、不断优化产品内容和服务&#xff0c;才能真正满足客户的需求。 近日&#xff0c;第十三届中国轻工…

想要跳槽涨薪 那你准备拿下 Framework 了吗?

2023这个阶段Android 还行&#xff0c;只是初级开发没有之前那么吃香了&#xff0c;初级市场饱和&#xff0c;但是中高级岗位人才还是比较稀缺。 我们Android程序员与其他程序员一样&#xff0c;每过一年焦虑便加深一点&#xff0c;在近几年越来越差的大环境下更是如此。许多程…

C++好难(2):类和对象(上篇)

okay&#xff0c;从这里开始&#xff0c;就进入c比较难的部分了~啊啊啊&#xff01;&#xff01;&#xff01; (﹃ԅ) 坚持坚持啦 ~ ᵎ(•̀㉨•́)و ̑̑ 【本章目标】 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 5.类的作用域 6.类的实…

情景剧本杀闯关系统

情景剧本杀闯关软件的开发需求通常包括以下几个方面&#xff1a; 剧本设计&#xff1a;开发者需要根据用户需求和市场调研&#xff0c;设计不同主题和难度等级的剧本内容&#xff0c;以及游戏过程中的任务、角色和道具等。 游戏引擎开发&#xff1a;为了实现游戏过程中…

TensoRT量化第四课:PTQ与QAT

目录 PTQ与QAT前言1. TensorRT量化2. PTQ3. QAT4. QAT实战4.1 环境配置4.2 pytorch_quantization简单示例4.3 自动插入QDQ节点 总结 PTQ与QAT 前言 手写AI推出的全新TensorRT模型量化课程&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考。 本次课程为第四课&am…

Netty基础(一)

1.概述 1.1.原生NIO存在的问题 1>.NIO的类库和API繁杂,使用麻烦: 需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等; 2>.需要具备其他的额外技能: 要熟悉Java多线程编程,因为NIO编程涉及到Reactor模式,你必须对多线程和网络编程非常熟悉,才能…

【数据结构与算法】图——邻接表与邻接矩阵

文章目录 一、图的基本概念二、图的存储结构2.1 邻接矩阵2.2 邻接表2.3 邻接矩阵的实现2.4 邻接表的实现 三、总结 一、图的基本概念 图&#xff08;Graph&#xff09;是由顶点的有穷非空集合和顶点之间边的集合组成&#xff0c;通常表示为&#xff1a;G&#xff08;V,E&#…

【服务器数据恢复】多块磁盘离线导致RAID5崩溃的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 某品牌StorageWorks存储设备&#xff0c;8块磁盘组建一组raid5磁盘阵列。存储中2块磁盘掉线导致阵列崩溃&#xff0c;经过检查发现掉线的2块磁盘均存在物理故障。 服务器数据恢复过程&#xff1a; 1、硬件工程师对掉线的两块磁盘进行…

性能测试-压力测试如何快速上手?8年资深测试总结整理,永不背锅...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 一般我们在刚介入…

mulesoft MCIA 破釜沉舟备考 2023.05.04.30(易错题)

mulesoft MCIA 破釜沉舟备考 2023.05.04.30(易错题) 1. According to MuleSoft, which major benefit does a Center for Enablement (C4E) provide for an enterprise and its lines of business?2. An organization is choosing between API-led connectivity and other i…