Skip to content

Bug: <title>SQLAlchemyDTO JSONB type bug #4497

@yxlwfds

Description

@yxlwfds

Description

1. SQLAlchemyDTO 与 JSONB 字段序列化错误

问题描述

使用 SQLAlchemyDTO 处理包含 JSONB 类型字段的模型时,出现以下错误:

ValueError: dictionary update sequence element #0 has length 1; 2 is required

HTTP 响应返回 500 Internal Server Error。

发生场景

  • 框架版本: Litestar 2.x (包括 2.15.1 和 2.18.0)
  • 数据库: PostgreSQL (使用 JSONB)
  • 模型定义: 字段被定义为 Mapped[dict[str, Any]]Mapped[dict]
  • 触发时机: DTO 序列化模型数据返回给客户端时

URL to code causing the issue

No response

MCVE

### 有问题的代码


from typing import Any
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column

class MyModel(Base):
    # 这种定义会导致 DTO 序列化出错
    config: Mapped[dict[str, Any]] = mapped_column(JSONB, default=dict)

Steps to reproduce

原因分析

Litestar DTO 生成器在处理 Mapped[dict[...]] 类型时,会尝试对数据进行严格的类型验证和转换。对于 JSONB 字段,底层处理逻辑可能错误地将数据视为需要解包的序列,导致转换失败。

解决方案

将字段的类型提示修改为 Mapped[Any]

from typing import Any
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column

class MyModel(Base):
    # 修改类型提示为 Any,绕过 DTO 的类型检查
    config: Mapped[Any] = mapped_column(JSONB, default=dict)

影响

  • 数据库: 无影响,依然是 JSONB 类型
  • API 文档: OpenAPI 中该字段可能显示为通用对象类型
  • 类型检查: IDE 不会提供字典相关的代码提示

2. SQLAlchemyDTO 循环引用错误

问题描述

当模型之间存在双向关系时,DTO 序列化可能导致无限递归或错误。

解决方案

SQLAlchemyDTOConfig 中排除反向引用字段:

class ParentReadDTO(SQLAlchemyDTO[Parent]):
    config = SQLAlchemyDTOConfig(
        exclude={
            "created_at", 
            "updated_at", 
            "children.parent",  # 排除子对象中的父引用
        },
        max_nested_depth=1,  # 限制嵌套深度
    )

示例

# 模型定义
class TemplateSuite(Base):
    items: Mapped[list[TemplateSuiteItem]] = relationship(back_populates="suite")

class TemplateSuiteItem(Base):
    suite: Mapped[TemplateSuite] = relationship(back_populates="items")

# DTO 配置 - 排除 items.suite 避免循环
class TemplateSuiteReadDTO(SQLAlchemyDTO[TemplateSuite]):
    config = SQLAlchemyDTOConfig(
        exclude={
            "created_at", 
            "updated_at", 
            "items.created_at", 
            "items.updated_at", 
            "items.suite",  # 关键:打破循环引用
        },
        max_nested_depth=1,
    )

Screenshots

No response

Logs


Litestar Version

Litestar 2.18.0 + advanced-alchemy 1.8.0
Mapped[dict] ❌
Mapped[dict[str, Any]] ❌
Mapped[Any] ✅

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug 🐛This is something that is not working as expected

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions