You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Postgres自定义triple_lang类型在Pydantic+SQLModel栈中返回列表问题求助

解决Postgres复合类型映射为SQLModel对象的问题

1. 修正字段不匹配的核心问题

你定义的Postgres复合类型triple_lang字段为(en text, fr text, es text),但Python侧TripleLang类的字段是en, ru, uk,字段名完全不对应,这是导致类型转换异常的关键之一,先统一字段:

from typing import Optional
from sqlmodel import SQLModel

class TripleLang(SQLModel, table=False):
    en: Optional[str] = None
    fr: Optional[str] = None
    es: Optional[str] = None

    class Config:
        from_attributes = True

2. 配置SQLAlchemy复合类型与自动转换

方式一:在模型层实现自动转换

利用SQLModel的from_orm方法,在查询后自动将PG返回的元组/列表转为TripleLang对象:

from sqlalchemy_utils import CompositeType
from sqlmodel import SQLModel, Field
from typing import Optional

# 定义与PG复合类型匹配的CompositeType
triple_lang_type = CompositeType(
    'triple_lang',
    [
        ('en', SQLModel.sqlalchemy_column_type(str)),
        ('fr', SQLModel.sqlalchemy_column_type(str)),
        ('es', SQLModel.sqlalchemy_column_type(str)),
    ]
)

class DataExtended(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    title: Optional[TripleLang] = Field(sa_column=triple_lang_type())
    description: Optional[TripleLang] = Field(sa_column=triple_lang_type())

    @classmethod
    def from_orm(cls, obj):
        instance = super().from_orm(obj)
        # 把元组/列表转换为TripleLang对象
        if isinstance(instance.title, (tuple, list)):
            instance.title = TripleLang(en=instance.title[0], fr=instance.title[1], es=instance.title[2])
        if isinstance(instance.description, (tuple, list)):
            instance.description = TripleLang(en=instance.description[0], fr=instance.description[1], es=instance.description[2])
        return instance

方式二:自定义SQLAlchemy类型转换器

创建自定义类型,继承CompositeType并实现结果处理器,自动完成类型转换:

from sqlalchemy_utils import CompositeType
from sqlalchemy import TypeDecorator
from sqlmodel import SQLModel, Field
from typing import Optional

class TripleLangType(TypeDecorator):
    impl = CompositeType(
        'triple_lang',
        [
            ('en', SQLModel.sqlalchemy_column_type(str)),
            ('fr', SQLModel.sqlalchemy_column_type(str)),
            ('es', SQLModel.sqlalchemy_column_type(str)),
        ]
    )

    def result_processor(self, dialect, coltype):
        base_processor = self.impl.result_processor(dialect, coltype)
        def process(value):
            if value is None:
                return None
            # 将PG返回的元组转为TripleLang对象
            return TripleLang(en=value[0], fr=value[1], es=value[2])
        return process

# 在表模型中使用自定义类型
class DataExtended(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    title: Optional[TripleLang] = Field(sa_column=TripleLangType())
    description: Optional[TripleLang] = Field(sa_column=TripleLangType())

3. 确保psycopg2复合类型注册正确

使用psycopg2注册复合类型时,要指定完整的类型名(带schema,比如public.triple_lang),并全局生效:

import psycopg2
from psycopg2.extensions import register_composite

# 建立数据库连接后执行注册
conn = psycopg2.connect("你的数据库连接字符串")
register_composite('public.triple_lang', conn.cursor(), globally=True)

4. 验证查询结果

执行查询后检查字段类型:

from sqlmodel import Session, select

with Session(engine) as session:
    data = session.exec(select(DataExtended)).first()
    print(type(data.title))  # 应输出 <class '__main__.TripleLang'>
    print(data.title.en)  # 可直接访问字段

内容的提问来源于stack exchange,提问作者Denis Shvetsov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 10:41:09