约束与默认值

约束保证数据的合法性,默认值简化插入操作。

一、完整示例

from sqlalchemy import Column, Integer, String, Boolean, DateTime
from datetime import datetime
from database import Base


class User(Base):
    __tablename__ = "users"

    id         = Column(Integer, primary_key=True, index=True)
    name       = Column(String(50), nullable=False)
    email      = Column(String(100), unique=True, nullable=False)
    age        = Column(Integer, default=0)
    is_active  = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

二、约束详解

1. primary_key — 主键

id = Column(Integer, primary_key=True)
  • 一条记录的唯一标识,不可重复、不可为空
  • 通常用自增整数,也可以用 UUID 等

2. nullable — 是否允许为空

name = Column(String(50), nullable=False)   # 不允许为空(数据库层面的 NOT NULL)
name = Column(String(50), nullable=True)    # 允许为空(默认值就是 True)
  • 这是数据库层面的约束,不是 Python 层面的
  • 即使 Python 代码不传这个字段,插入时数据库也会报错

3. unique — 唯一约束

email = Column(String(100), unique=True)
  • 同一张表中不能有两条记录的 email 相同
  • 适合邮箱、手机号、身份证号等业务上不能重复的字段

4. index — 索引

name = Column(String(50), index=True)
  • 加速查询,但会稍微拖慢写入
  • 经常出现在 WHERE 条件中的字段建议加索引
  • primary_keyunique 字段自动带索引,不需要额外加

5. 复合唯一约束

from sqlalchemy import UniqueConstraint

class User(Base):
    __tablename__ = "users"
    id    = Column(Integer, primary_key=True)
    name  = Column(String(50))
    email = Column(String(100))

    # name + email 组合不能重复
    __table_args__ = (
        UniqueConstraint("name", "email", name="uq_name_email"),
    )
  • 单独的 name 可以重复,单独的 email 也可以重复
  • 但 name + email 的组合不能重复

三、默认值详解

1. default — Python 层默认值

age = Column(Integer, default=0)
  • 在 Python 代码中插入数据时,如果不指定 age,自动填 0
  • 这是 Python 层面的行为,SQLAlchemy 在生成 INSERT 语句时填入

2. server_default — 数据库层默认值

from sqlalchemy import text

created_at = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"))
  • 直接在数据库中设置默认值,不依赖 Python
  • 即使用其他工具(如 Navicat、命令行)插入数据也会生效
  • 常用于 CURRENT_TIMESTAMPUUID() 等数据库函数

3. default vs server_default 的区别

defaultserver_default
生效层Python 代码数据库
非 Python 插入❌ 不生效✅ 生效
能用 Python 表达式✅ 能❌ 不能
常用场景业务默认值时间戳、数据库函数

4. onupdate — 更新时自动填充

updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
  • default=datetime.now:创建时自动填入当前时间
  • onupdate=datetime.now:每次调用 db.commit() 更新这条记录时,自动刷新为当前时间
  • 适合做「最后更新时间」字段

5. 使用 Python 函数做默认值

import uuid

# 注意:传的是函数本身 uuid.uuid4,不是调用结果 uuid.uuid4()
token = Column(String(36), default=uuid.uuid4)
  • default=函数名(不加括号),SQLAlchemy 会在插入时调用它
  • 如果写成 default=uuid.uuid4(),那所有记录的 token 都一样,因为只算了一次