【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:安装依赖

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

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

步骤 2:配置数据库连接

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

python 复制代码
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,可以自动处理这些字段。

python 复制代码
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 字段。

python 复制代码
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 等框架时非常有用,能够轻松验证并序列化数据。

python 复制代码
from pydantic import BaseModel
from datetime import datetime

# 用户创建输入数据模型
class UserCreate(BaseModel):
    name: str
    email: str

# 用户响应输出数据模型
class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    created_at: datetime
    updated_at: datetime
    
    class Config:
        orm_mode = True

解释

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

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

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

python 复制代码
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.name
        db_user.email = user.email
        db.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() 方法可以自动创建表格:

python 复制代码
# 创建所有定义的表
Base.metadata.create_all(bind=engine)

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

python 复制代码
# 创建数据库 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)

完整代码示例

python 复制代码
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__ = True
    id = 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: str
    email: str

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    created_at: datetime
    updated_at: datetime

    class 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.name
        db_user.email = user.email
        db.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 等框架时。

相关推荐
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou3 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书3 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
----云烟----4 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024064 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
小二·4 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
i道i5 小时前
MySQL win安装 和 pymysql使用示例
数据库·mysql
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud