【Python】使用 Pydantic + SQLAlchemy + MySQL 实现自动记录创建时间和更新时间

使用 Pydantic + SQLAlchemy + MySQL 实现自动记录创建时间和更新时间

在 Web 应用开发中,自动记录数据库中的 创建时间更新时间 是常见的需求。无论是日志记录、数据跟踪,还是审计功能,这类时间戳都至关重要。本文将介绍如何结合 SQLAlchemyPydantic,在使用 MySQL 作为数据库时,自动处理数据插入和更新时的时间戳。

技术栈

  • MySQL:作为数据库,保存数据记录。
  • SQLAlchemy:用于操作数据库的 ORM 工具,使得开发者可以通过 Python 类来操作数据库表。
  • Pydantic:用于数据验证和序列化,常用于 FastAPI 等 Web 框架。
  • MySQL Connector:通过 MySQL Connector 或 pymysql 作为 MySQL 的驱动。

需求分析

每个表记录需要包含两个时间字段:

  1. 创建时间 (created_at):记录数据首次插入数据库的时间,只在插入时设置一次。
  2. 更新时间 (updated_at):记录数据最近一次被修改的时间,在每次修改时自动更新。

目标是通过 SQLAlchemy 自动处理这两个字段,并且结合 Pydantic 验证和返回数据。

步骤 1:安装依赖

首先,确保你已经安装了以下必要的库:

pip install sqlalchemy pydantic pymysql mysql-connector-python
  • SQLAlchemy:用于与数据库交互。
  • Pydantic:用于数据模型验证。
  • PyMySQLmysql-connector-python:作为 MySQL 的驱动。

步骤 2:配置数据库连接

我们使用 SQLAlchemycreate_engine 来连接 MySQL 数据库。假设你已经在 MySQL 中创建了名为 test_db 的数据库。

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker# MySQL 数据库连接
DATABASE_URL = "mysql+pymysql://username:password@localhost:3306/test_db"# 创建 SQLAlchemy 的 Engine
engine = create_engine(DATABASE_URL)# 创建数据库 session
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)# 基础模型类
Base = declarative_base()

步骤 3:定义包含时间戳的基础模型

接下来我们创建一个基础模型,该模型包含 created_atupdated_at 字段。通过 SQLAlchemyColumnDateTime,可以自动处理这些字段。

from sqlalchemy import Column, Integer, DateTime, func# 创建带有时间戳的基础模型
class TimestampMixin:created_at = Column(DateTime, default=func.now(), nullable=False)updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False)# 用户自定义基础类,所有模型继承自该类
class BaseModel(Base, TimestampMixin):__abstract__ = True  # 该模型不被映射到数据库id = Column(Integer, primary_key=True, index=True)

解释

  • TimestampMixin: 该类包含 created_atupdated_at 两个字段。created_at 使用 default=func.now() 确保在首次插入数据时自动设置当前时间;updated_at 使用 onupdate=func.now() 确保在每次数据更新时自动更新为当前时间。
  • BaseModel: 作为其他数据模型的基础类,包含 id 字段以及从 TimestampMixin 继承的时间戳字段。

步骤 4:定义具体的数据模型

下面我们定义一个用户模型 User,它继承了 BaseModel,并且包含用户的 nameemail 字段。

from sqlalchemy import Column, String# 用户模型
class User(BaseModel):__tablename__ = 'users'# 用户字段name = Column(String(50), nullable=False)email = Column(String(120), unique=True, nullable=False)

解释

  • User 模型继承自 BaseModel,因此它自动拥有 idcreated_atupdated_at 字段。
  • nameemail 是用户模型的其他字段,分别用于存储用户的名字和邮箱地址。

步骤 5:Pydantic 数据模型

为了确保输入数据的验证和输出数据的格式化,我们使用 Pydantic 创建输入和输出数据模型。Pydantic 在结合 FastAPI 等框架时非常有用,能够轻松验证并序列化数据。

from pydantic import BaseModel
from datetime import datetime# 用户创建输入数据模型
class UserCreate(BaseModel):name: stremail: str# 用户响应输出数据模型
class UserResponse(BaseModel):id: intname: stremail: strcreated_at: datetimeupdated_at: datetimeclass Config:orm_mode = True

解释

  • UserCreate: 用于验证创建用户时输入的数据,包含 nameemail
  • UserResponse: 用于返回给客户端的数据模型,包含 idnameemail 以及 created_atupdated_at
  • orm_mode = True: 允许 Pydantic 从 SQLAlchemy 模型自动生成 Pydantic 模型实例。

步骤 6:实现数据库插入和更新操作

在插入和更新数据时,我们使用 SQLAlchemySession 来操作数据,同时时间戳字段会自动更新。

from sqlalchemy.orm import Session# 创建新用户
def create_user(db: Session, user: UserCreate):db_user = User(name=user.name, email=user.email)db.add(db_user)db.commit()db.refresh(db_user)  # 获取插入后的最新字段(包括 id 和时间戳)return db_user# 更新用户信息
def update_user(db: Session, user_id: int, user: UserCreate):db_user = db.query(User).filter(User.id == user_id).first()if db_user:db_user.name = user.namedb_user.email = user.emaildb.commit()db.refresh(db_user)  # 确保更新时间戳自动更新return db_user

解释

  • create_user: 创建新的用户,并通过 db.commit() 提交数据。db.refresh() 刷新用户对象,确保返回的对象包含最新的 id 和时间戳。
  • update_user: 根据 user_id 查找用户并更新用户信息,db.commit() 会自动更新 updated_at 字段。

步骤 7:创建数据库表并进行操作

在操作数据库之前,我们需要确保数据库表已存在。通过 SQLAlchemy 的 Base.metadata.create_all() 方法可以自动创建表格:

# 创建所有定义的表
Base.metadata.create_all(bind=engine)

之后,可以通过创建 Session 并调用上述的 create_userupdate_user 函数来操作数据:

# 创建数据库 Session
db = SessionLocal()# 创建用户
new_user = UserCreate(name="Alice", email="alice@example.com")
created_user = create_user(db, new_user)
print(created_user)# 更新用户
updated_user = update_user(db, created_user.id, UserCreate(name="Alice Updated", email="alice.updated@example.com"))
print(updated_user)

完整代码示例

from sqlalchemy import create_engine, Column, Integer, String, DateTime, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from pydantic import BaseModel
from sqlalchemy.orm import Session
from datetime import datetime# MySQL 数据库连接
DATABASE_URL = "mysql+pymysql://username:password@localhost:3306/test_db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()# 带有时间戳的基础模型
class TimestampMixin:created_at = Column(DateTime, default=func.now(), nullable=False)updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False)# 基础模型类
class BaseModel(Base, TimestampMixin):__abstract__ = Trueid = Column(Integer, primary_key=True, index=True)# 用户模型
class User(BaseModel):__tablename__ = 'users'name = Column(String(50), nullable=False)email = Column(String(120), unique=True, nullable=False)# 创建所有表
Base.metadata.create_all(bind=engine)# Pydantic 输入输出模型
class UserCreate(BaseModel):name: stremail: strclass UserResponse(BaseModel):id: intname: stremail: strcreated_at: datetimeupdated_at: datetimeclass Config:orm_mode = True# 创建新用户
def create_user(db: Session, user: UserCreate):db_user = User(name=user.name, email=user.email)db.add(db_user)db.commit()db.refresh(db_user)return db_user# 更新用户
def update_user(db: Session, user_id: int, user: UserCreate):db_user = db.query(User).filter(User.id == user_id).first()if db_user:db_user.name = user.namedb_user.email = user.emaildb.commit()db.refresh(db_user)return db_user# 使用数据库
db = SessionLocal()
new_user = UserCreate(name="Alice", email="alice@example.com")
created_user = create_user(db, new_user)
print(created_user)updated_user = update_user(db, created_user.id, UserCreate(name="Alice Updated", email="alice.updated@example.com"))
print(updated_user)

总结

通过以上步骤,我们实现了在使用 MySQL 作为数据库时,结合 SQLAlchemyPydantic 自动记录创建时间和更新时间的功能。SQLAlchemy 负责数据库操作,Pydantic 负责数据验证和序列化,两者结合使得代码更加简洁和安全。在现代 Web 应用开发中,这种模式非常实用,尤其是在使用 FastAPI 等框架时。

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

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

相关文章

网站可疑问题

目标站点 Google hack 页面访问 抓包 POST /admin.php?actionlogin HTTP/2 Host: www.xjy.edu.cn Cookie: xkm_sidA6x4Cgw2zx User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0 Accept: text/html,application/xhtmlxml,appl…

使用 Light Chaser 进行大屏数据可视化

引言 在当今数据驱动的世界中,数据可视化变得越来越重要。Light Chaser 是一款基于 React 技术栈的大屏数据可视化设计工具,通过简单的拖拽操作,你可以快速生成漂亮、美观的数据可视化大屏和看板。本文将介绍如何使用 Light Chaser 进行数据…

Redis:string类型

Redis:string类型 string命令设置与读取SETGETMSETMGET 数字操作INCRINCRBYDECRDECRBYINCRBYFLOAT 字符串操作APPENDSTRLENGETRANGESETRANGE 内部编码intembstrraw 在Redis中,字符串string存储的是二进制,以byte为单位,输入的二进…

【HTML+CSS】留言板plus实现全过程

创建一个具有动态留言的简约风格留言板 在本教程中,我们将学习如何创建一个简约风格的留言板,它具备动态留言显示和一些基本动画效果。这个留言板将使用HTML和CSS构建,最终实现一个既美观又实用的界面。 准备工作 首先,确保你的…

面试速通宝典——7

150. 数据库连接池的作用 数据库连接池的作用包括以下几个方面: 资源重用:连接池允许多个客户端共享有限的数据库连接,减少频繁创建和销毁连接的开销,从而提高资源的利用率。 统一的连接管理:连接池集中管理数据库连…

Stream流的终结方法(一)

1.Stream流的终结方法 2.forEach 对于forEach方法,用来遍历stream流中的所有数据 package com.njau.d10_my_stream;import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.function.Consumer; import java.util…

Swagger配置且添加小锁(asp.net)(笔记)

此博客是基于 asp.net core web api(.net core3.1)框架进行操作的。 一、安装Swagger包 在 NuGet程序包管理中安装下面的两个包: swagger包:Swashbuckle.AspNetCore swagger包过滤器:Swashbuckle.AspNetCore.Filters 二、swagger注册 在…

戴尔PowerEdge R840服务器亮黄灯 不开机

最近接修到一台东莞用户的DELL PowerEdge R840 服务器因为意外断电后,无法正常开机的问题, 大概故障现象是 插上电源线 按卡机按钮无响应,无法开机,无显示输出,工程师到现场检修,经过idrac中日志分析&#…

K8S真正删除pod

假设k8s的某个命名空间如(default)有一个运行nginx 的pod,而这个pod是以kubectl run pod命令运行的 1.错误示范: kubectl delete pod nginx-2756690723-hllbp 结果显示这个pod 是删除了,但k8s很快自动创建新的pod,但是…

C(九)while循环 --- 军训匕首操情景

匕首操,oi~oi~oi~~~~~ 接下来的几篇推文,杰哥记录的是三大循环结构的运行流程及其变式。 本篇的主角是while循环。👉 目录: while循环 的组成、运行流程及其变式关键字break 和 continue 在while 循环中的作用while 循环的嵌套题目…

基于SSM的坚果金融投资管理系统、坚果金融投资管理平台的设计与开发、智慧金融投资管理系统的设计与实现、坚果金融投资管理系统的设计与应用研究(源码+定制+开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

我为什么决定关闭ChatGPT的记忆功能?

你好,我是三桥君 几个月前,ChatGPT宣布即将推出一项名为“记忆功能”的新特性,英文名叫memory。 这个功能听起来相当吸引人,宣传口号是让GPT更加了解用户,仿佛是要为我们每个人量身打造一个专属的AI助手。 在记忆功…

vue结合element-ui实现列表拖拽变化位置,点击拖动图标拖动整个列表元素,使用tsx格式编写

先来看下需要实现的效果 当鼠标放在左侧图标上时,可以拖动整个列表元素,调整顺序 思路介绍 使用draggable可以设置元素可拖动,然后分别设置三个事件处理函数,监听onDragstart、onDragover、onDragend三个事件 注意&#xff1a…

青少年科普教学系统小程序的设计

管理员账户功能包括:系统首页,个人中心,管理员管理,基础数据管理,作品信息管理,通知公告管理,视频信息管理,系统管理 微信端账号功能包括:系统首页,视频信息&…

html+css+js实现Collapse 折叠面板

实现效果&#xff1a; HTML部分 <div class"collapse"><ul><li><div class"header"><h4>一致性 Consistency</h4><span class"iconfont icon-jiantou"></span></div><div class"…

【unity进阶知识6】Resources的使用,如何封装一个Resources资源管理器

文章目录 一、Unity资源加载的几种方式1、Inspector窗口拖拽2、Resources3、AssetBundle4、Addressables&#xff08;可寻址资源系统&#xff09;5、AssetDatabase 二、准备三、同步加载Resources资源1、Resources.Load同步加载单个资源1.1、基本加载1.2、加载指定类型的资源1.…

泛型编程--模板【C++提升】(特化、类属、参数包的展开、static、模板机制、重载......你想知道的全都有)

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 本文所在专栏&#xff1a; C系列语法知识_Stark、的博客-CSDN博客 其它专栏&#xff1a; 数据结构与算法_Stark、的博客-CSDN博客 C系列项目实战_Stark、的博客-CSDN博客 座右铭&#xff1a;梦…

国外电商系统开发-运维系统批量添加服务器

您可以把您准备的txt文件&#xff0c;安装要求的格式&#xff0c;复制粘贴到里面就可以了。注意格式&#xff01; 如果是“#” 开头的&#xff0c;则表示注释&#xff01;

网盘能否作为FTP替代产品?企业该如何进行FTP国产化替代?

近年来&#xff0c;信创的概念引入和高效实践落地让更多的行业企业自发性地进行国产化替代&#xff0c;目前信创国产化替代还多发生在操作系统和应用层面&#xff0c;软件工具等目前还在下一阶段规划&#xff0c;但很多企业未雨绸缪&#xff0c;已经在做调研和尝试。 FTP作为世…

一些 Go Web 开发笔记

原文&#xff1a;Julia Evans - 2024.09.27 在过去的几周里&#xff0c;我花了很多时间在用 Go 开发一个网站&#xff0c;虽然不知道它最终会不会发布&#xff0c;但在这个过程中我学到了一些东西&#xff0c;想记录下来。以下是我的一些收获&#xff1a; Go 1.22 现在有了更…