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. 类声明部分

  • 这里引用的DIFY Account表的数据库,列举详细的参数定义
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 是当前租户下的角色,是计算属性,不是数据库字段



参考链接:


目录
相关文章
|
5天前
|
存储 JavaScript 前端开发
JavaScript基础
本节讲解JavaScript基础核心知识:涵盖值类型与引用类型区别、typeof检测类型及局限性、===与==差异及应用场景、内置函数与对象、原型链五规则、属性查找机制、instanceof原理,以及this指向和箭头函数中this的绑定时机。重点突出类型判断、原型继承与this机制,助力深入理解JS面向对象机制。(238字)
|
4天前
|
云安全 人工智能 安全
阿里云2026云上安全健康体检正式开启
新年启程,来为云上环境做一次“深度体检”
1590 6
|
6天前
|
安全 数据可视化 网络安全
安全无小事|阿里云先知众测,为企业筑牢防线
专为企业打造的漏洞信息收集平台
1325 2
|
5天前
|
缓存 算法 关系型数据库
深入浅出分布式 ID 生成方案:从原理到业界主流实现
本文深入探讨分布式ID的生成原理与主流解决方案,解析百度UidGenerator、滴滴TinyID及美团Leaf的核心设计,涵盖Snowflake算法、号段模式与双Buffer优化,助你掌握高并发下全局唯一ID的实现精髓。
348 160
|
5天前
|
人工智能 自然语言处理 API
n8n:流程自动化、智能化利器
流程自动化助你在重复的业务流程中节省时间,可通过自然语言直接创建工作流啦。
408 6
n8n:流程自动化、智能化利器
|
7天前
|
人工智能 API 开发工具
Skills比MCP更重要?更省钱的多!Python大佬这观点老金测了一周终于懂了
加我进AI学习群,公众号右下角“联系方式”。文末有老金开源知识库·全免费。本文详解Claude Skills为何比MCP更轻量高效:极简配置、按需加载、省90% token,适合多数场景。MCP仍适用于复杂集成,但日常任务首选Skills。推荐先用SKILL.md解决,再考虑协议。附实测对比与配置建议,助你提升效率,节省精力。关注老金,一起玩转AI工具。
|
14天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
1549 7
|
4天前
|
Linux 数据库
Linux 环境 Polardb-X 数据库 单机版 rpm 包 安装教程
本文介绍在CentOS 7.9环境下安装PolarDB-X单机版数据库的完整流程,涵盖系统环境准备、本地Yum源配置、RPM包安装、用户与目录初始化、依赖库解决、数据库启动及客户端连接等步骤,助您快速部署运行PolarDB-X。
252 1
Linux 环境 Polardb-X 数据库 单机版 rpm 包 安装教程
|
9天前
|
人工智能 前端开发 API
Google发布50页AI Agent白皮书,老金帮你提炼10个核心要点
老金分享Google最新AI Agent指南:让AI从“动嘴”到“动手”。Agent=大脑(模型)+手(工具)+协调系统,可自主完成任务。通过ReAct模式、多Agent协作与RAG等技术,实现真正自动化。入门推荐LangChain,文末附开源知识库链接。
676 119