0

0

高效将SQLAlchemy模型转换为JSON的策略与实践

霞舞

霞舞

发布时间:2025-10-05 09:38:28

|

535人浏览过

|

来源于php中文网

原创

高效将SQLAlchemy模型转换为JSON的策略与实践

在构建Python后端API时,将SQLAlchemy ORM模型对象转换为JSON格式是常见的需求,尤其是在处理具有继承关系或复杂关联的模型时。本文将深入探讨三种现代且高效的方法:使用SQLAlchemy-serializer混入、Pydantic进行数据验证与序列化,以及SQLModel框架,帮助开发者轻松实现模型到JSON的转换,并有效管理数据结构与关系。

引言:SQLAlchemy模型JSON序列化的挑战

在开发web api时,后端通常需要将从数据库查询到的sqlalchemy模型对象发送给前端。然而,sqlalchemy模型对象并非原生json可序列化的。直接尝试使用json.dumps()会遇到类型错误。虽然可以通过编写自定义的as_dict方法将模型转换为字典,但这种方法对于包含继承关系、一对多或多对多关联的复杂模型而言,往往无法全面捕获所有相关字段,导致数据不完整或需要手动递归处理,效率低下且容易出错。因此,我们需要更强大、更灵活的工具来处理这类序列化任务。

本文将介绍三种主流且现代的解决方案,它们能够优雅地解决SQLAlchemy模型(包括关联和继承字段)到JSON的转换问题。

1. 使用 SQLAlchemy-serializer 混入

SQLAlchemy-serializer是一个轻量级的库,通过提供一个混入(Mixin)类,使得SQLAlchemy模型能够方便地序列化为字典或JSON。它特别擅长处理模型间的关系和递归序列化。

核心概念与使用

通过继承SerializerMixin,你的SQLAlchemy模型将自动获得to_dict()方法。这个方法能够将模型及其关联对象(如果配置得当)转换为Python字典,然后你可以使用json.dumps()将其转换为JSON字符串。

示例代码

首先,确保安装了SQLAlchemy-serializer:

pip install SQLAlchemy-serializer

然后,在你的Base声明式基类中混入SerializerMixin:

import json
from sqlalchemy import ForeignKey, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, sessionmaker
from sqlalchemy_serializer import SerializerMixin

# 声明式基类,混入 SerializerMixin
class Base(DeclarativeBase, SerializerMixin):
    pass

# 定义项目模型
class Project(Base):
     __tablename__="projects"
     id: Mapped[int] = mapped_column(primary_key=True)
     name: Mapped[str]
     owner_id: Mapped[int] = mapped_column(ForeignKey("users.id"))

# 定义用户模型
class User(Base):
    __tablename__="users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    # 定义与Project模型的一对多关系
    projects: Mapped[list[Project]] = relationship(backref="owner")
    # 序列化规则:停止对projects.owner的递归,避免无限循环
    serialize_rules = ('-projects.owner',)  

# 数据库初始化与会话管理
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
session_maker = sessionmaker(bind=engine)

with session_maker() as session:
    user = User(name="User1")

    # 添加关联项目
    user.projects.append(Project(name="Project 1"))
    user.projects.append(Project(name="Project 2"))

    session.add(user)
    session.commit()
    session.refresh(user) # 刷新对象以加载关系

    # 将用户模型及其关联项目序列化为JSON
    print(json.dumps(user.to_dict()))

输出示例

{"id": 1, "projects": [{"id": 1, "name": "Project 1", "owner_id": 1}, {"id": 2, "name": "Project 2", "owner_id": 1}], "name": "User1"}

注意事项

  • serialize_rules: 这是SQLAlchemy-serializer的一个强大功能。通过设置规则,你可以控制哪些字段应该被包含或排除,以及在处理关系时何时停止递归,以避免无限循环(例如,User有Project,Project又通过owner指向User)。-projects.owner表示在序列化Project时,不包含其owner字段,从而切断了循环。
  • 性能: 对于非常大的数据集和复杂的嵌套关系,需要注意序列化深度可能带来的性能开销。

2. 使用 Pydantic 进行数据验证与序列化

Pydantic是一个强大的Python数据验证和设置管理库。它允许你使用Python类型提示来定义数据模式(Schema),并能自动进行数据验证、序列化和反序列化。结合SQLAlchemy,Pydantic提供了一种清晰且类型安全的方式来定义API响应的数据结构。

核心概念与使用

Pydantic通过BaseModel定义数据模式。你可以为每个SQLAlchemy模型创建一个对应的Pydantic模型,并利用ConfigDict(from_attributes=True)(或旧版Pydantic的Config.orm_mode = True)来指示Pydantic从ORM对象中读取属性。

示例代码

首先,确保安装了pydantic:

pip install pydantic

然后,定义SQLAlchemy模型和对应的Pydantic模型:

from sqlalchemy import ForeignKey, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, sessionmaker
from pydantic import BaseModel, ConfigDict
import json # Pydantic v2+ BaseModel.model_dump_json() handles JSON serialization directly

class Base(DeclarativeBase):
    pass

# SQLAlchemy模型
class Project(Base):
     __tablename__="projects"
     id: Mapped[int] = mapped_column(primary_key=True)
     name: Mapped[str]
     owner_id: Mapped[int] = mapped_column(ForeignKey("users.id"))

class User(Base):
    __tablename__="users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    projects: Mapped[list[Project]] = relationship(backref="owner")

# Pydantic模型
class ProjectScheme(BaseModel):
    # 允许Pydantic从ORM对象的属性中读取值
    model_config = ConfigDict(from_attributes=True) 
    id: int
    name: str

class UserScheme(BaseModel):
    model_config = ConfigDict(from_attributes=True)
    id: int
    name: str
    # 关联字段也需要定义为Pydantic模型列表
    projects: list[ProjectScheme]

# 数据库初始化与会话管理
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
session_maker = sessionmaker(bind=engine)

with session_maker() as session:
    user = User(name="User1")

    user.projects.append(Project(name="Project 1"))
    user.projects.append(Project(name="Project 2"))

    session.add(user)
    session.commit()
    session.refresh(user)

    # 使用Pydantic模型验证并序列化SQLAlchemy对象
    # Pydantic v2+ 使用 model_validate 和 model_dump_json
    user_json = UserScheme.model_validate(user).model_dump_json()

    print(user_json)

输出示例

{"id":1,"name":"User1","projects":[{"name":"Project 1","id":1},{"name":"Project 2","id":2}]}

注意事项

  • model_config = ConfigDict(from_attributes=True): 这是Pydantic v2+ 中启用ORM模式的关键。它告诉Pydantic,当传入的数据不是字典而是ORM对象时,可以从对象的属性中获取值。
  • 显式Schema定义: Pydantic要求你为API响应显式定义数据模式。这增加了代码量,但也带来了强类型检查和清晰的API文档(尤其与FastAPI结合时)。
  • 关系处理: 对于关联对象,你需要像projects: list[ProjectScheme]这样在Pydantic模型中也显式地定义其对应的Pydantic模式。
  • Pydantic V1 vs V2: Pydantic v2引入了ConfigDict和model_validate/model_dump_json等新API。请根据你使用的Pydantic版本调整代码。

3. 使用 SQLModel

SQLModel是一个由FastAPI的创建者开发的库,它旨在将SQLAlchemy和Pydantic的优势结合起来,提供一个统一的、声明式的ORM和数据验证框架。使用SQLModel可以显著减少模型定义中的冗余。

Cutout.Pro抠图
Cutout.Pro抠图

AI批量抠图去背景

下载

核心概念与使用

在SQLModel中,你的模型既是SQLAlchemy的表定义,又是Pydantic的数据模式。这意味着你只需定义一次模型,它就能同时处理数据库交互和数据序列化。

示例代码

首先,确保安装了sqlmodel:

pip install sqlmodel

然后,定义SQLModel模型:

from typing import Optional
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlmodel import SQLModel, Field, Relationship
import json # SQLModel models also have .model_dump_json()

# 定义项目的基础模型(Pydantic部分)
class ProjectBase(SQLModel):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str

# 定义完整的项目模型(SQLAlchemy表 + Pydantic)
class Project(ProjectBase, table=True):
    __tablename__="projects" # 显式指定表名
    owner_id: Optional[int] = Field(default=None, foreign_key="users.id")
    # 定义与User模型的关系
    owner: "User" = Relationship(back_populates="projects")


# 定义用户的基础模型(Pydantic部分)
class UserBase(SQLModel):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str

# 定义完整的用户模型(SQLAlchemy表 + Pydantic)
class User(UserBase, table=True):
    __tablename__="users" # 显式指定表名
    # 定义与Project模型的关系
    projects: list[Project] = Relationship(back_populates="owner")

# 定义用于输出的用户模型,通常用于控制API响应中包含哪些关联数据
class UserOutput(UserBase):
    projects: list[ProjectBase] = [] # 输出时包含项目列表,但只包含ProjectBase的字段

# 数据库初始化与会话管理
engine = create_engine("sqlite://")
SQLModel.metadata.create_all(engine) # 使用SQLModel的metadata创建所有表
session_maker = sessionmaker(bind=engine)

with session_maker() as session:
    user = User(name="User1")

    user.projects.append(Project(name="Project 1"))
    user.projects.append(Project(name="Project 2"))

    session.add(user)
    session.commit()
    session.refresh(user)

    # 使用UserOutput模型验证并序列化SQLModel对象
    print(UserOutput.model_validate(user).model_dump_json())

输出示例

{"id":1,"name":"User1","projects":[{"name":"Project 1","id":1},{"name":"Project 2","id":2}]}

注意事项

  • 模型统一: SQLModel的最大优势在于将ORM模型和Pydantic模型合二为一,减少了代码冗余。
  • table=True: 在模型类定义中添加table=True,指示SQLModel这是一个需要映射到数据库表的模型。
  • Relationship: SQLModel使用Relationship来定义模型之间的关系,类似于SQLAlchemy的relationship。
  • UserOutput: 为了控制API响应中关联数据的深度和字段,可以定义一个只包含必要字段的Pydantic模型(如UserOutput),它继承自UserBase并包含ProjectBase列表,而不是完整的Project模型。这有助于避免不必要的循环引用和过多的数据暴露。
  • 类型提示: SQLModel heavily relies on Python type hints for both database schema and Pydantic validation.

总结与选择建议

将SQLAlchemy模型转换为JSON是API开发中的一项基本任务。选择哪种方法取决于项目的具体需求和团队偏好:

  1. SQLAlchemy-serializer:

    • 优点: 侵入性小,只需混入SerializerMixin即可使用。通过serialize_rules灵活控制序列化深度和字段。
    • 缺点: 缺少Pydantic的数据验证功能。主要用于序列化,不涉及数据验证。
    • 适用场景: 现有SQLAlchemy项目,需要快速添加JSON序列化功能,且对数据验证要求不高。
  2. Pydantic:

    • 优点: 强大的数据验证和类型检查能力。清晰地定义API响应结构,有助于生成API文档。与FastAPI集成度高。
    • 缺点: 需要为每个SQLAlchemy模型额外定义一个Pydantic模型,存在一定的代码冗余。
    • 适用场景: 新项目,特别是使用FastAPI的项目,对数据验证和API文档有严格要求,希望通过Pydantic模型严格控制API输入输出。
  3. SQLModel:

    • 优点: 统一了ORM和Pydantic模型定义,最大限度减少了冗余。同时具备SQLAlchemy的ORM能力和Pydantic的数据验证能力。
    • 缺点: 相对较新,生态系统不如纯SQLAlchemy或纯Pydantic成熟。对Python类型提示有较高要求。
    • 适用场景: 新项目,希望实现ORM和API数据模型的高度统一,追求简洁和效率,并愿意采用较新的技术

无论选择哪种方法,理解其工作原理和适用场景都至关重要。通过合理运用这些工具,你可以构建出高效、健壮且易于维护的Python API。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

420

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

536

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

313

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

Python FastAPI异步API开发_Python怎么用FastAPI构建异步API
Python FastAPI异步API开发_Python怎么用FastAPI构建异步API

Python FastAPI 异步开发利用 async/await 关键字,通过定义异步视图函数、使用异步数据库库 (如 databases)、异步 HTTP 客户端 (如 httpx),并结合后台任务队列(如 Celery)和异步依赖项,实现高效的 I/O 密集型 API,显著提升吞吐量和响应速度,尤其适用于处理数据库查询、网络请求等耗时操作,无需阻塞主线程。

27

2025.12.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

340

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1503

2023.10.24

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.7万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号