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 是当前租户下的角色,是计算属性,不是数据库字段



参考链接:


目录
相关文章
|
6月前
|
IDE 数据库 开发工具
SQLALCHEMY中DeclarativeBase,MappedAsDataclass
Python 中 SQLAlchemy 中这一开源库的使用方法
296 3
|
5月前
|
数据采集 人工智能 网络安全
OpenClaw-MedAgent实战指南:阿里云1分钟部署+医学文献智能检索全流程(2026版)
在医学研究与临床实践中,文献检索、数据整理与技术分析是核心环节,但传统人工方式存在效率低、信息碎片化、数据挖掘不深入等痛点。2026年,基于OpenClaw框架构建的医学文献AI助手(OpenClaw-MedAgent)应运而生,凭借模块化架构与多模型适配能力,实现医学文献自动化检索、核心原理提炼、数据资源整合与报告生成,成为医护人员、科研学者的高效工具。
1472 19
|
5月前
|
人工智能 自然语言处理 运维
不懂代码照样造网站,老金15万字Claude Code+OpenClaw教程免费开源
春节期间,零代码基础的老金仅凭语音指令,用Claude Code(武器)和OpenClaw(助理)协同打造了全功能网站aiking.dev。现将两套工具中文教程合并升级为《Claude-Code-x-OpenClaw-Guide-Zh》,10万字免费开源,覆盖从造轮子到调度千军万马的完整AI编程路径。
|
4月前
|
数据管理 API
ISBN书号查询-ISBN图书查询-ISBN书号解析API接口介绍
ISBN是国际标准书号,13位唯一标识符,相当于图书“身份证”。含前缀、国家区号、出版社码、书序号及校验码。用于版本区分、全球流通、出版准入与数据管理。支持API查询书名、作者、出版社等全量元数据。
1543 0
|
5月前
|
IDE API 数据库
FastAPI + SQLModel 实战:标准项目结构下,一个模型搞定数据库与 API
SQLModel 实现“一模型双用”:单个类同时作为数据库表与 Pydantic API 模型,天然支持字段校验、类型提示、OpenAPI 文档生成,彻底消除重复定义,提升开发效率与一致性。(239字)
662 4
|
6月前
|
存储 自然语言处理 数据库
RAG(检索增强生成)技术简介
RAG(检索增强生成)通过结合信息检索与文本生成,提升大模型回答的准确性与时效性。它利用向量数据库实现语义检索,支持智能客服、医疗诊断、法律咨询等场景,解决知识更新难、专业性不足等问题,并以“按需取用”机制突破上下文限制,兼顾效率与隐私。
1032 4
|
7月前
|
运维 监控 数据可视化
15-Portainer轻量级图形化监控 Portainer:Docker轻量级可视化工具
Portainer是一款轻量级Docker图形化管理工具,支持单机与集群环境,提供开源(CE)和商业版(BE/EE)。通过Docker部署,映射端口并挂载卷后即可运行,访问9000端口可进入界面。首次使用需创建管理员账号,可直观管理镜像、容器、网络、数据卷及Stack编排,简化运维操作。
|
SQL 数据库 开发者
Python中使用Flask-SQLAlchemy对数据库的增删改查简明示例
这样我们就对Flask-SQLAlchemy进行了一次简明扼要的旅程,阐述了如何定义模型,如何创建表,以及如何进行基本的数据库操作。希望你在阅读后能对Flask-SQLAlchemy有更深入的理解,这将为你在Python世界中从事数据库相关工作提供极大的便利。
1030 77
|
10月前
|
前端开发 Java 开发者
MVC 架构模式技术详解与实践
本文档旨在全面解析软件工程中经典且至关重要的 MVC(Model-View-Controller) 架构模式。内容将深入探讨 MVC 的核心思想、三大组件的职责与交互关系、其优势与劣势,并重点分析其在现代 Web 开发中的具体实现,特别是以 Spring MVC 框架为例,详解其请求处理流程、核心组件及基本开发实践。通过本文档,读者将能够深刻理解 MVC 的设计哲学,并掌握基于该模式进行 Web 应用开发的能力。
1872 1

热门文章

最新文章