Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
解决SQLAlchemy/SQLModel中UUID主键映射为字符串的问题_创想鸟

解决SQLAlchemy/SQLModel中UUID主键映射为字符串的问题

解决SQLAlchemy/SQLModel中UUID主键映射为字符串的问题

本文探讨了在使用SQLAlchemy或SQLModel时,数据库中的UUID(如SQL Server的UNIQUEIDENTIFIER)字段在检索时被错误地映射为Python字符串而非uuid.UUID对象的问题。文章提供了两种解决方案:一是简单的客户端手动转换,二是更推荐且专业的SQLAlchemy TypeDecorator自定义类型映射,确保数据类型在Python应用中保持一致性,从而避免类型错误并提升代码健壮性。

1. 问题描述

在使用sqlmodel或sqlalchemy与数据库交互时,尤其当数据库中存储的是uuid类型(例如sql server的uniqueidentifier),我们可能会遇到一个常见的类型映射问题。尽管在模型定义中将主键指定为uuid.uuid类型,但在从数据库检索数据时,该字段却被映射为python的str类型。这会导致在代码中进行类型检查或直接操作uuid.uuid对象时出现错误。

考虑以下使用SQLModel定义的模型:

import uuidfrom typing import Optionalfrom sqlmodel import Field, SQLModelfrom sqlalchemy import Column, text# 假设 DescriptionConstants 是一个常量类,此处为简化省略其定义class GUIDModel(SQLModel):    """    为使用GUID作为主键的表提供基础混入    """    guid: Optional[uuid.UUID] = Field(        ...,        primary_key=True,        # description=DescriptionConstants.GUID, # 假设存在,此处省略        sa_column=Column(            "guid",            # UNIQUEIDENTIFIER, # 假设这是从某个特定数据库方言导入的类型,如mssql.UNIQUEIDENTIFIER            # 为了通用性,此处可以先不指定具体的DB类型,或者使用String/CHAR            nullable=False,            primary_key=True,            server_default=text("newsequentialid()"), # SQL Server特有的生成GUID函数        ),    )class Project(GUIDModel, table=True):    name: str = Field(max_length=255, description="项目名称")

当尝试检索数据并验证guid字段的类型时,会遇到类型不匹配的错误:

# 示例测试代码import unittestfrom sqlmodel import Session, create_engine# 假设 __get_engine() 返回一个SQLAlchemy引擎实例def __get_engine():    # 示例:使用SQLite内存数据库,实际应用中替换为您的数据库连接    return create_engine("sqlite:///:memory:")class ProjectTests(unittest.TestCase):    def setUp(self):        engine = __get_engine()        SQLModel.metadata.create_all(engine)        with Session(engine) as session:            # 插入一个测试项目            project = Project(name="Test Project")            session.add(project)            session.commit()            session.refresh(project)            self.test_project_guid = project.guid    def test_get_project(self):        engine = __get_engine()        with Session(engine) as session:            # 假设 Projects._get_project 是一个获取项目的方法            # 简化为直接查询            project: Project = session.query(Project).filter(Project.guid == self.test_project_guid).first()            # 预期类型为 uuid.UUID,但实际可能是 str            self.assertEqual(type(project.guid), uuid.UUID)# 运行测试可能得到以下错误:#  != # Expected :# Actual   :

这个错误明确指出,尽管我们期望project.guid是一个uuid.UUID对象,但它实际上是一个str。这通常发生在SQLAlchemy或其驱动程序将数据库中的UUID字符串直接映射为Python字符串,而没有进行自动的uuid.UUID对象转换。

2. 解决方案

解决此问题主要有两种策略:客户端手动转换和使用SQLAlchemy自定义类型。

2.1 策略一:客户端手动转换(简单但不推荐)

最直接的方法是在每次从数据库获取数据后,手动将字符串形式的UUID转换回uuid.UUID对象。

示例代码:

import uuid# 假设从数据库获取的 guid_str 是一个字符串guid_str_from_db = "a1b2c3d4-e5f6-7890-1234-567890abcdef"# 转换为 uuid.UUID 对象my_uuid_object = uuid.UUID(guid_str_from_db)print(f"转换后的GUID: {my_uuid_object}, 类型: {type(my_uuid_object)}")

在您的_get_project方法或任何检索逻辑中,您可以这样处理:

# 假设这是您的项目获取方法def _get_project(session: Session) -> Project:    project_from_db = session.query(Project).first() # 获取第一个项目    if project_from_db and isinstance(project_from_db.guid, str):        # 手动转换        project_from_db.guid = uuid.UUID(project_from_db.guid)    return project_from_db# 在测试中:# project: Project = Projects._get_project(session)# self.assertEqual(type(project.guid), uuid.UUID) # 现在应该通过

注意事项:

优点: 简单易行,不需要修改模型定义。缺点: 每次获取数据都需要手动转换,代码重复且容易遗漏,不符合DRY(Don’t Repeat Yourself)原则。当模型字段较多或在多个地方使用时,维护成本高。

2.2 策略二:使用SQLAlchemy TypeDecorator 自定义类型(推荐)

这是更专业和健壮的解决方案。SQLAlchemy提供了TypeDecorator,允许我们定义自定义的数据类型,并在Python对象和数据库类型之间进行双向转换。通过这种方式,可以在ORM层面自动处理str到uuid.UUID的转换。

步骤:

定义自定义UUID类型: 创建一个继承自TypeDecorator的类,并实现process_bind_param(Python到DB)和process_result_value(DB到Python)方法。在模型中使用自定义类型: 将模型字段的sa_column指定为这个自定义类型。

示例代码:

import uuidfrom typing import Optionalfrom sqlmodel import Field, SQLModel, Session, create_enginefrom sqlalchemy import Column, textfrom sqlalchemy.types import TypeDecorator, CHAR# 如果针对SQL Server的UNIQUEIDENTIFIER,可以导入:# from sqlalchemy.dialects import mssqlclass UUIDType(TypeDecorator):    """    平台无关的UUID类型。    在数据库中存储为CHAR(36),并在Python中映射为uuid.UUID对象。    """    # 指定数据库底层类型。对于UUID,通常存储为36字符的字符串(如 "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx")。    # 如果目标数据库有原生UUID类型(如PostgreSQL),可以设置为sqlalchemy.dialects.postgresql.UUID。    # 对于SQL Server的UNIQUEIDENTIFIER,它在SQLAlchemy层面通常也表现为字符串,所以CHAR(36)是通用的。    impl = CHAR(36)     cache_ok = True # 提高SQLAlchemy 1.4+版本的性能    def process_bind_param(self, value, dialect):        """        将Python的uuid.UUID对象转换为字符串,以便存储到数据库。        """        if value is None:            return value        if not isinstance(value, uuid.UUID):            # 如果传入的不是uuid.UUID对象,尝试将其转换为UUID对象            try:                value = uuid.UUID(value)            except ValueError:                raise ValueError(f"预期 uuid.UUID 或 UUID 字符串,但得到 {type(value)}: {value}")        return str(value) # 转换为字符串以便存入数据库    def process_result_value(self, value, dialect):        """        将从数据库获取的字符串值转换为Python的uuid.UUID对象。        """        if value is None:            return value        if isinstance(value, uuid.UUID):            return value # 如果已经是UUID对象,直接返回        if isinstance(value, str):            # 处理数据库中可能存在的空字符串或无效UUID字符串            if value.strip() == '':                return None # 或者根据业务需求抛出异常            try:                return uuid.UUID(value)            except ValueError:                # 如果从数据库获取的字符串不是有效的UUID,可以记录日志或抛出异常                raise ValueError(f"从数据库获取的UUID字符串无效: '{value

以上就是解决SQLAlchemy/SQLModel中UUID主键映射为字符串的问题的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1366922.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Python屏蔽输出信息如何隐藏 print 语句的打印内容 Python屏蔽输出信息的基础操作技巧​
上一篇 2025年12月14日 06:58:32
查看Python版本怎样在命令行用简写命令查询 查看Python版本的简写命令实用方法​
下一篇 2025年12月14日 06:58:47

相关推荐

  • ​​VSCode的终极骚操作!学会这些让你的编程效率无人能敌

    掌握VSCode的高效技巧能显著提升编程效率。首先利用代码片段(Snippets)避免重复输入,如设置“rcomp”快速生成React组件结构;接着通过Emmet缩写大幅提升HTML/CSS编写速度,如“ul>li*3”生成列表;再结合Prettier、ESLint等插件优化代码质量与格式;自…

    2026年9月22日
    300
  • GPU 使用率低下的成因分析与排查解决指南

    GPU使用率低不等于显卡未工作,可能是任务流程中存在等待或瓶颈。先检查驱动是否更新、电源模式是否设为高性能、显卡连接与散热是否正常;再分析是否存在CPU预处理慢、存储速度低或频繁I/O导致GPU等待;最后优化应用设置,如提升画质、关闭垂直同步、减少后台占用。问题多出在流程瓶颈而非显卡性能不足。 GP…

    2026年9月22日
    100
  • 荣耀官宣!谢霆锋成荣耀Mgaic8系列代言人

    今日,荣耀正式宣布谢霆锋担任“未来科技体验官”,并曝光其手持荣耀magic8 pro的宣传画面。 据知名数码博主@数码闲聊站透露,该机型将采用一块6.71英寸的1.5K等深四曲面屏幕,集成3D人脸识别与3D超声波指纹解锁功能,带来更安全便捷的交互体验。续航方面,新机内置高达7200mAh的青海湖电池…

    2026年9月22日
    000
  • 安装 pyinstaller 出错的解决办法及 csdn 工具实例打包

    安装 pyinstaller 出错的解决办法及 csdn 工具实例打包安装 pyinstaller 出错的解决办法及 csdn 工具实例打包安装 pyinstaller 出错的解决办法及 csdn 工具实例打包安装 pyinstaller 出错的解决办法及 csdn 工具实例打包

    想要解决安装 pyinstaller 时遇到的问题,并了解如何使用它打包 csdn 工具实例吗?请继续阅读本文。 首先,前往 PyInstaller 的官方网站下载安装包:https://www.php.cn/link/87067b6ae6205be72c631e0f370391f7 解压后,将文件…

    2026年9月22日 用户投稿
    300
  • Java项目中利用.class文件:Classpath配置与接口实现

    在Java项目中引用并实现来自.class文件的接口是常见的需求,尤其当仅提供编译后的字节码文件时。本文将深入讲解Java Classpath的核心概念及其重要性,并提供在命令行环境下配置Classpath的详细步骤和示例,确保编译器和JVM能够正确找到并加载所需的.class文件,从而顺利完成接口…

    2026年9月22日
    700
  • MySQL安装时端口冲突如何解决?

    MySQL安装时端口冲突如何解决?MySQL安装时端口冲突如何解决?MySQL安装时端口冲突如何解决?MySQL安装时端口冲突如何解决?

    mysql安装时3306端口冲突的解决方法有两类:1.修改mysql默认端口;2.找出并停止占用端口的进程。在安装过程中可通过mysql安装向导直接修改端口号,或安装后编辑配置文件my.ini(windows)或my.cnf(linux)中的port参数,并重启mysql服务生效。若确认3306应为…

    2026年9月22日 用户投稿
    800
  • safari浏览器怎么阻止网站访问剪贴板_safari浏览器阻止网站访问剪贴板方法

    可通过关闭网站剪贴板权限、启用无痕浏览、禁用JavaScript或使用内容拦截扩展来阻止Safari网站访问剪贴板,保护隐私安全。 如果您在使用 Safari 浏览器时发现某些网站尝试自动读取或写入剪贴板内容,可能会导致隐私泄露或意外粘贴敏感信息。为防止此类行为,您可以采取以下措施限制网站对剪贴板的…

    2026年9月22日
    1800
  • Linux进程调度学习!

    进程调度决定了哪个进程将被执行以及执行的时间,操作系统通过合理的进程调度实现资源的最大化利用。 在单片机上,常见的方式是系统初始化后进入 while(1){} 循环。当然,单片机也可以运行类似 FreeRTOS 的系统,从而实现进程切换。 在带有操作系统的 CPU 上运行的逻辑是允许多个进程(实际上…

    2026年9月22日
    000
  • ​​VSCode高手才知道的骚操作!学会这些技巧开发快人一步​​

    掌握VSCode效率核心在于命令面板、自定义快捷键、多光标编辑、代码片段与扩展生态;通过减少鼠标依赖、实现快速跳转与自动化操作,构建专属高效开发环境,让注意力聚焦于代码思维而非工具操作。 VSCode里那些让你效率翻倍的“骚操作”,本质上是将开发流程中的重复性、高频操作进行极致的简化与自动化。它不是…

    2026年9月22日
    300
  • 工信部批复:eSIM 手机业务全网开通,暂不支持线上方式

    10 月 14 日消息,据 c114 通讯网报道,中国电信、中国联通与中国移动已于今日正式获得批准,可开展 esim 手机运营服务的商用试验。 根据三大运营商公布的相关信息,eSIM 手机服务将覆盖全国 31 个省、自治区及直辖市,并正式进入市场销售阶段。 需要注意的是,在此次商用试验阶段,暂不支持…

    2026年9月22日
    000
  • CanvaPro中AI生成图片如何导出为PDF?快速保存图像的方法

    在Canva Pro中导出AI生成图片为PDF,需先将图片添加至设计,点击“分享”→“下载”→选择“PDF标准”或“PDF打印”即可。2. PDF标准适用于在线分享,文件小、加载快;PDF打印适用于高质量印刷,支持300 DPI和CMYK色彩模式,确保色彩准确与细节清晰。3. 为保证AI图片导出质量…

    2026年9月22日
    200
  • Laravel 文件上传:解决数据库存储物理路径而非可访问 URL 的问题

    本教程旨在解决 laravel 文件上传后,数据库中存储文件物理路径而非可访问 url 的常见问题。通过分析 move() 方法的返回值,并引入 url() 辅助函数,我们将演示如何正确地将文件移动到指定目录,同时确保数据库记录的是可供前端访问的图片资源链接,从而避免图片无法正常显示。 在 Lara…

    2026年9月22日
    100
  • windows怎么更改计算机工作组_Windows计算机工作组修改方法

    首先通过系统属性修改工作组名称,右键“此电脑”选择属性,进入高级系统设置的计算机名选项卡进行更改并重启;其次可用管理员命令提示符执行wmic命令批量配置,输入指定命令后重启生效;最后专业版用户可通过组策略编辑器,在启动脚本中添加指令实现自动加入工作组。 如果您需要将Windows计算机加入或更改到特…

    2026年9月22日
    000
  • 机械键盘轴体深度手感分析:线性轴、段落轴与提前段落轴

    机械键盘手感取决于轴体类型,主流分为线性轴、段落轴和提前段落轴。线性轴直上直下顺滑连贯,代表如Cherry MX Red,适合游戏与快速输入;段落轴中程有明显阻力峰,提供清晰反馈,如Cherry MX Blue,适合文字工作;提前段落轴起步阻力大随后变轻,如TTC Gold Pink,防误触且节奏独…

    2026年9月22日
    000
  • 实现Java双向路径搜索的正确方法

    本文旨在帮助开发者理解并正确实现Java中的双向路径搜索算法。通过分析常见的实现错误,我们将提供一种清晰、可行的解决方案,并详细解释如何构建完整的路径,克服单向搜索树的局限性,从而实现从起点到终点的完整路径搜索。 双向路径搜索是一种优化路径搜索效率的策略,它同时从起点和终点开始搜索,并在中间相遇。然…

    2026年9月22日
    900
  • VSCode设置Markdown写作环境(实用技巧,排版美化指南)

    要在vscode里打造舒服又高效的markdown写作环境,答案是通过安装核心扩展并进行个性化配置来实现;需安装markdown all in one、markdown preview enhanced、prettier和paste image等扩展,结合settings.json中的编辑器设置、自…

    2026年9月22日
    100
  • 如何用Filmora制作高质量AI视频?简易AI视频剪辑的实用指南

    如何用Filmora制作高质量AI视频?简易AI视频剪辑的实用指南如何用Filmora制作高质量AI视频?简易AI视频剪辑的实用指南如何用Filmora制作高质量AI视频?简易AI视频剪辑的实用指南如何用Filmora制作高质量AI视频?简易AI视频剪辑的实用指南

    Filmora的AI功能通过AI Copilot脚本生成、AI文本转视频、AI语音、图像生成、智能抠像及音频优化等工具,显著提升视频制作效率与专业度,尤其在视觉处理、听觉优化和创意辅助方面表现突出;关键在于将AI作为辅助起点,避免过度依赖,结合人工精修,才能实现高质量AI视频创作。 ☞☞☞AI 智能…

    2026年9月22日 用户投稿
    400
  • 好用的终端复用神器-Tmux

    好用的终端复用神器-Tmux好用的终端复用神器-Tmux好用的终端复用神器-Tmux好用的终端复用神器-Tmux

    前言 许久之前就听说过tmux,但是一直没上手,直到最近需要一直在linux下完成一些任务,我才切实感受到了tmux的优点:任意分屏、保存工作 就单单这两点,就足够实用了。分屏,曾今还十分痴迷i3wm和dwm这样的窗口管理工具,尤其是dwm的操作逻辑,大大提升linux工作效率。其他详情可以查看阮一…

    2026年9月22日 用户投稿
    100
  • VS Code启动优化:扩展延迟加载与缓存策略

    合理管理扩展加载与缓存可显著提升VS Code启动速度。通过配置activationEvents实现按需激活、利用Extension Storage和CachedDataDir优化数据读取,并禁用非核心扩展,结合“Developer: Show Running Extensions”分析耗时,有效缩…

    2026年9月22日
    100
  • 星纪魅族万志强回应魅族22影像升级:10月还会有OTA

    10月13日,星纪魅族集团中国区cmo万志强就用户对魅族22手机影像表现的积极评价作出回应。他表示,本月还将推送新一轮ota更新,届时魅族22的影像性能有望再次提升。 魅族22 据CNMO消息,有用户反馈称:尽管魅族22在发布时拍照能力并非顶尖,但通过数月的系统优化,其影像水准已达到主流旗舰机型80…

    2026年9月22日
    000

发表回复

登录后才能评论
关注微信