Flask中定义类使用Sqlalchemy时,mapped_column详细讲解

简介: 本文详解 SQLAlchemy 2.0 中 `mapped_column` 的用法,介绍其语法结构、常用参数(如 `nullable`、`default`、`server_default`、`onupdate` 等),并通过 DIFY 的 Account 模型实例解析字段定义逻辑,对比数据库列与运行时字段的区别,帮助理解 ORM 映射机制。

1. mapped_column 语法解析

mapped_column 是 SQLAlchemy 2.0 的写法,用于定义数据库列。

基本语法结构

字段名: Mapped[类型] = mapped_column(列类型, 参数1=值1, 参数2=值2, ...)

  • 字段名:Python 属性名
  • Mapped[类型]:类型提示,表示该字段的类型
  • mapped_column(...):定义数据库列

1.1那如何导入呢 ?

from sqlalchemy.orm import mapped_column

# mapped_column 是 sqlalchemy.orm 模块中的一个函数

1.2具体位置在哪里 ?

sqlalchemy/

 └── orm/

     ├── mapped_column  ← 这里!

     ├── Mapped

     ├── DeclarativeBase

     ├── MappedAsDataclass

     └── ... 其他 ORM 相关类



相关导入对比

在后面的 Account 类中,同时导入了:

from sqlalchemy.orm import Mapped, Session, mapped_column
  • Mapped:类型提示类,用于类型注解
  • Session:数据库会话类
  • mapped_column:函数,用于定义数据库列


mapped_column 常用参数说明

参数 说明 示例
一个位置参数 列类型(必需) String(255), DateTimeStringUUID
nullable 是否允许 NULL,数据库的值 nullable=True
default Python 默认值 default=Nonedefault="active"
server_default 据库默认值 server_default=func.current_timestamp()
init 是否在 __init__ 中生成参数,默认值是init = True【如果不写】。

# 创建对象时,不需要传入这些字段


init=False
onupdate

onupdate 表示:当记录被更新时,数据库自动将该字段设置为指定值。

onupdate=func.current_timestamp()
primary_key 是否为主键 primary_key=True



详细解释 Account 类的定义,重点说明 mapped_column 的用法:

Account 类定义详解

2. 类声明部分

from sqlalchemy.orm import DeclarativeBase,MappedAsDataclass
from models.engine import metadata

class TypeBase(DeclarativeBase,MappedAsDataclass):
    metadata = metadata

    
    
from sqlalchemy.orm import Mapped, mapped_column
class Account(UserMixin, TypeBase):
    __tablename__ = "accounts"
    __table_args__ = (sa.PrimaryKeyConstraint("id", name="account_pkey"), sa.Index("account_email_idx", "email"))

    id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"), init=False)
    name: Mapped[str] = mapped_column(String(255))
    email: Mapped[str] = mapped_column(String(255))
    password: Mapped[str | None] = mapped_column(String(255), default=None)
    password_salt: Mapped[str | None] = mapped_column(String(255), default=None)
    avatar: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None)
    interface_language: Mapped[str | None] = mapped_column(String(255), default=None)
    interface_theme: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None)
    timezone: Mapped[str | None] = mapped_column(String(255), default=None)
    last_login_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None)
    last_login_ip: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None)
    last_active_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.current_timestamp(), nullable=False, init=False
    )
    status: Mapped[str] = mapped_column(
        String(16), server_default=sa.text("'active'::character varying"), default="active"
    )
    initialized_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None)
    created_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.current_timestamp(), nullable=False, init=False
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.current_timestamp(), nullable=False, init=False, onupdate=func.current_timestamp()
    )

    role: TenantAccountRole | None = field(default=None, init=False)
    _current_tenant: "Tenant | None" = field(default=None, init=False)
    
    
 UserMixin:Flask-Login 的混入,提供用户认证相关方法
TypeBase:SQLAlchemy 基类(支持 dataclass 特性)
__tablename__:数据库表名
__table_args__:表级约束(主键、索引等)



3. 字段详解(逐行)

字段 1:id(主键)

id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"), init=False)
  • Mapped[str]:Python 类型为字符串
  • StringUUID:自定义类型(UUID 字符串)
  • server_default=sa.text("uuid_generate_v4()"):数据库默认值(PostgreSQL 函数)
  • init=False:dataclass 特性,不在 __init__生成该参数

含义:主键,数据库自动生成 UUID,创建对象时不需要传入。


字段 2:name(用户名)

name: Mapped[str] = mapped_column(String(255))
  • Mapped[str]:字符串类型
  • String(255):VARCHAR(255)
  • 无其他参数:必填、可空为 False、无默认

含义:用户名,最大 255 字符,必填。


字段 3:email(邮箱)

email: Mapped[str] = mapped_column(String(255))

与 name 相同,必填字符串字段。


字段 4:password(密码)

password: Mapped[str | None] = mapped_column(String(255), default=None)
  • Mapped[str | None]:可为字符串或 None
  • default=None:Python 默认值为 None
  • 未设置 nullable=True:数据库层面仍为 NOT NULL(需显式设置 nullable=True

含义:密码,可为空,Python 默认 None。


字段 5:avatar(头像)

avatar: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None)
  • nullable=True:数据库允许 NULL
  • default=None:Python 默认 None

含义:头像 URL,数据库和 Python 都允许为空。


字段 6:last_active_at(最后活跃时间)

last_active_at: Mapped[datetime] = mapped_column(
    DateTime, server_default=func.current_timestamp(), nullable=False, init=False
)
  • DateTime:日期时间类型
  • server_default=func.current_timestamp():数据库默认当前时间
  • nullable=False:不允许 NULL
  • init=False:不在 __init__ 中生成参数

含义:最后活跃时间,数据库自动设置为当前时间,创建时不需要传入。


字段 7:status(状态)

status: Mapped[str] = mapped_column(
    String(16), server_default=sa.text("'active'::character varying"), default="active"
)
  • String(16):最大 16 字符
  • server_default=sa.text("'active'::character varying"):数据库默认 'active'
  • default="active":Python 默认 'active'

含义:状态,数据库和 Python 都有默认值 'active'。


字段 8:updated_at(更新时间)

updated_at: Mapped[datetime] = mapped_column(
    DateTime, server_default=func.current_timestamp(), nullable=False, init=False, onupdate=func.current_timestamp()
)
  • onupdate=func.current_timestamp():更新时自动设置为当前时间

含义:更新时间,创建和更新时自动设置。


4. 特殊字段(非数据库字段)

role: TenantAccountRole | None = field(default=None, init=False)

_current_tenant: "Tenant | None" = field(default=None, init=False)

  • field():dataclass 的字段定义
  • init=False:不在 __init__ 中生成参数
  • 这些字段不存储在数据库中,用于运行时状态

5.为什么created_at、last_active_atlast_login_at 没有 onupdate


5.1.为什么 created_at 没有 onupdate

created_at: Mapped[datetime] = mapped_column(
    DateTime, server_default=func.current_timestamp(), nullable=False, init=False
)

# 注意:没有 onupdate 参数

原因:创建时间应该永远不变。如果加了 onupdate,每次更新都会改变创建时间,这是不合理的设计原则:

  • created_at:记录创建时间,永远不变
  • updated_at:记录最后更新时间,每次更新都改变


5.2.last_login_at 的定义

last_login_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None)

  • 没有 onupdate:不会在每次更新时自动设置
  • 没有 server_default:数据库不会自动生成
  • 可空:允许为 None

为什么这样设计?

只在用户登录时设置,不是每次更新都更新

需要业务代码显式设置:account.last_login_at = datetime.now()


5.3. last_active_at 的定义

last_active_at: Mapped[datetime] = mapped_column(

   DateTime, server_default=func.current_timestamp(), nullable=False, init=False

)

  • server_default:创建时自动设置
  • 没有 onupdate:不会在每次更新时自动更新


为什么这样设计?

  • 只在特定操作时更新(如用户活跃时),不是每次数据库更新都更新
  • 需要业务代码显式设置account.last_active_at = datetime.now()


总结

  1. mapped_column 定义数据库列
  2. Mapped[类型] 提供类型提示
  3. default 是 Python 默认值,server_default 是数据库默认值
  4. init=False 表示该字段不在构造函数中
  5. nullable=True 允许数据库中的 NULL

onupdate 在更新时自动设置值


Account 表字段 onupdate 对比

字段名 onupdate server_default nullable init 原因说明
id StringUUID ❌ 无 ✅ uuid_generate_v4() False False 主键,创建后不变
name String(255) ❌ 无 ❌ 无 False True 业务字段,手动更新
email String(255) ❌ 无 ❌ 无 False True 务字段,手动更新
password String(255) ❌ 无 ❌ 无 False True 业务字段,手动更新
password_salt String(255) ❌ 无 ❌ 无 False True 务字段,手动更新
avatar String(255) ❌ 无 True True 业务字段,手动更新
interface_language String(255) ❌ 无 ❌ 无 False True 业务字段,手动更新
interface_theme String(255) ❌ 无 True True 业务字段,手动更新
timezone String(255) ❌ 无 ❌ 无 False True 业务字段,手动更新
last_login_at DateTime ❌ 无 ❌ 无 True True 仅在登录时更新
last_login_ip String(255) ❌ 无 ❌ 无 True True 仅在登录时更新
last_active_at DateTime ✅ current_timestamp() False False 仅在活跃时更新
status String(16) ✅ 'active' False True 业务字段,手动更新
initialized_at DateTime ❌ 无 True True 仅在初始化时更
created_at DateTime ❌ 无 ✅ current_timestamp() False False 创建时间,不应改变
updated_at DateTime ✅ current_timestamp() ✅ current_timestamp() False False 每次更新时自动更新




Question:name 字段没有定义其他属性值,那它的默认值分别有哪些 ?

name: Mapped[str] = mapped_column(String(255)

如果只写这些,各参数的默认值如下:

参数 实际值 说明
列类型 String(255) ✅ 已指定
nullable False 因为 Mapped[str](非可选类型)
default None 未指定,默认 None
server_default None 指定,默认 None
init True 未指定,默认 True
onupdate None 未指定,默认 None
primary_key False 未指定,默认 False


# 定义
name: Mapped[str] = mapped_column(String(255))

# 等价于(显式写法)
name: Mapped[str] = mapped_column(
    String(255),
    nullable=False,      # 默认值
    default=None,        # 默认值
    server_default=None, # 默认值
    init=True,           # 默认值
    onupdate=None,       # 默认值
    primary_key=False    # 默认值
)

使用 field 的字段(不存储在数据库)

role: TenantAccountRole | None = field(default=None, init=False)
_current_tenant: "Tenant | None" = field(default=None, init=False)

这些字段会:

  • 不在数据库表中创建列
  • 只存在于 Python 对象中
  • 用于运行时状态管理
  • 会持久化

为什么 Account 使用 field

看代码中的使用:

role: TenantAccountRole | None = field(default=None, init=False)
_current_tenant: "Tenant | None" = field(default=None, init=False)
@property
def current_tenant(self):
    return self._current_tenant
@current_tenant.setter
def current_tenant(self, tenant: "Tenant"):
    # ... 设置当前租户的逻辑
    self._current_tenant = tenant

原因:

  1. 运行时状态:current_tenant 表示当前会话的租户,不需要持久化
  2. 性能优化:避免每次都查询数据库
  3. 业务逻辑:role 是当前租户下的角色,是计算属性,不是数据库字段



参考链接:


目录
相关文章
|
2天前
|
存储 自然语言处理 数据库
RAG(检索增强生成)技术简介
RAG(检索增强生成)通过结合信息检索与文本生成,提升大模型回答的准确性与时效性。它利用向量数据库实现语义检索,支持智能客服、医疗诊断、法律咨询等场景,解决知识更新难、专业性不足等问题,并以“按需取用”机制突破上下文限制,兼顾效率与隐私。
101 4
|
4天前
|
存储 弹性计算 人工智能
2026 年阿里云服务器租用价格全解析:年付、月付收费标准与配置参考
阿里云服务器租用价格受实例类型、配置、计费周期影响,从低至 38 元 / 年的轻量机型到数万元 / 年的高性能实例不等。以下结合 2026 年最新收费标准,梳理轻量应用服务器、ECS 云服务器及 GPU 服务器的核心配置与多周期价格,覆盖年付、3 年付、月付及按量付费场景,帮助用户按需选择。
105 11
|
2天前
|
IDE 数据库 开发工具
SQLALCHEMY中DeclarativeBase,MappedAsDataclass
Python 中 SQLAlchemy 中这一开源库的使用方法
47 3
|
7天前
|
安全 算法 网络协议
从明文到加密:HTTP与HTTPS核心知识全解析
本文深入解析HTTP与HTTPS的核心差异,揭示HTTPS如何通过SSL/TLS协议、CA证书和混合加密机制,解决HTTP的窃听、篡改与冒充三大安全问题,全面科普网络安全关键技术。
333 6
|
9天前
|
存储 缓存 前端开发
HTTP 缓存详解
HTTP缓存是提升网页性能的核心机制,通过“强制缓存”和“协商缓存”减少请求、节省带宽。强制缓存由浏览器判断是否过期(如Cache-Control),未过期则直接使用本地资源;过期后进入协商缓存,服务器通过Etag或Last-Modified判定资源是否变更,可复用则返回304。合理配置缓存策略,能显著提升加载速度与用户体验。
105 3
|
21天前
|
人工智能 开发者
阿里云携手超90%金融机构,交出2025年度答卷
2025年,AI浪潮席卷而来,创新触手可及。值此年末,阿里云开启年度成绩单发布之旅。这是一份回顾,更是一声致谢——感恩每位客户与开发者的信赖相伴。砥砺前行,共赴智能未来!
94 10
|
21天前
|
消息中间件 人工智能 运维
事故写了一堆,还是天天踩坑?聊聊运维知识库自动化这件“迟早要补的课”
事故写了一堆,还是天天踩坑?聊聊运维知识库自动化这件“迟早要补的课”
104 7
|
2天前
|
机器学习/深度学习 算法 计算机视觉
基于yolov10的吸烟检测系统
本研究基于YOLOv10深度学习算法,构建高精度、实时化吸烟行为检测系统。针对传统方法在复杂场景下检测率低、效率差的问题,利用YOLOv10的动态稀疏注意力与多尺度融合优势,提升小目标与遮挡情况下的识别能力,结合五分类体系实现对香烟、烟雾、电子烟等多目标精准定位。系统支持GPU加速,达30帧/秒以上实时检测,可广泛应用于医院、机场等公共场所,助力无烟环境建设与智能安防升级,推动禁烟政策高效落地。