如何在SQLModel中动态设置含表名的SQL默认值?
解决方案
要实现动态将子类表名嵌入sequence_id的默认值,核心是利用declared_attr动态定义字段,而非静态声明——这样在子类继承时就能获取到当前子类的表名信息:
from sqlalchemy import Column, VARCHAR, text from sqlalchemy.ext.declarative import declared_attr from sqlmodel import SQLModel, Field, Optional from uuid import UUID class BaseModel(SQLModel): @declared_attr def __tablename__(cls) -> str: return cls.__name__ guid: Optional[UUID] = Field(default=None, primary_key=True) class SequencedBaseModel(BaseModel): @declared_attr def sequence_id(cls) -> str: # 直接通过cls获取子类的表名 return Field( sa_column=Column( VARCHAR(50), server_default=text(f"SELECT '{cls.__tablename__}_' + convert(varchar(10), NEXT VALUE FOR dbo.sequence)") ) ) # 定义Project表示例 class Project(SequencedBaseModel, table=True): name: str = Field(...)
关键细节说明
@declared_attr装饰sequence_id方法后,子类(如Project)继承时会触发该方法的执行,此时cls指向子类本身,能直接读取cls.__tablename__。- 生成的
server_default会自动替换为子类的表名,比如Project类对应的默认值就是SELECT 'Project_' + convert(varchar(10), NEXT VALUE FOR dbo.sequence),最终生成Project_1、Project_2这类格式的序列值。 - Alembic生成迁移脚本时,能正确识别每个子类的
sequence_id列对应的默认值——因为declared_attr在模型构建阶段就完成了动态求值,Alembic可以拿到最终的列定义。
迁移脚本验证
运行alembic revision --autogenerate生成迁移时,Project表的sequence_id列默认值会被正确生成为:
server_default=sa.text("SELECT 'Project_' + convert(varchar(10), NEXT VALUE FOR dbo.sequence)")
内容的提问来源于stack exchange,提问作者Matthias Burger
相关产品推荐
相关产品推荐

