模型配置

除了字段定义,Model 还有一些类级别的配置。

一、表名

class User(Base):
    __tablename__ = "users"
  • 必须显式指定,SQLAlchemy 不会自动命名
  • 习惯用复数小写:usersordersorder_items

二、表参数(table_args

__table_args__ 用来放表级别的配置,是一个元组或字典:

class User(Base):
    __tablename__ = "users"

    id   = Column(Integer, primary_key=True)
    name = Column(String(50))

    __table_args__ = (
        UniqueConstraint("name", name="uq_user_name"),   # 约束
        {"mysql_charset": "utf8mb4"},                     # 数据库特定参数
    )

常见用途:

# 1. 复合唯一约束
__table_args__ = (
    UniqueConstraint("col1", "col2", name="uq_col1_col2"),
)

# 2. 复合索引
from sqlalchemy import Index
__table_args__ = (
    Index("ix_name_email", "name", "email"),
)

# 3. MySQL 指定字符集
__table_args__ = (
    {"mysql_charset": "utf8mb4"},
)

# 4. 多个配置组合(元组 + 字典)
__table_args__ = (
    UniqueConstraint("name", name="uq_name"),
    Index("ix_email", "email"),
    {"mysql_charset": "utf8mb4"},
)

三、__repr__ — 调试输出

class User(Base):
    __tablename__ = "users"

    id   = Column(Integer, primary_key=True)
    name = Column(String(50))

    def __repr__(self):
        return f"<User(id={self.id}, name='{self.name}')>"
  • 不是必须的,但调试时 print(user) 会输出可读信息
  • 没有的话只能看到 <User object at 0x000002...> 这种无意义内容

四、完整 Model 模板

一个生产可用的 Model 通常长这样:

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


class Article(Base):
    __tablename__ = "articles"

    # 主键
    id = Column(Integer, primary_key=True, index=True)

    # 业务字段
    title   = Column(String(200), nullable=False)
    content = Column(Text, nullable=False)
    status  = Column(Integer, default=0)          # 0=草稿 1=已发布 2=已下架

    # 时间字段
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # 软删除标记(不用真删数据,标记一下就行)
    is_deleted = Column(Boolean, default=False)

    def __repr__(self):
        return f"<Article(id={self.id}, title='{self.title}')>"

1. 几个设计习惯

习惯说明
主键用 id简单直接,框架兼容性最好
时间用 created_at / updated_at一看就知道是什么时间
软删除用 is_deleted数据不真删,查的时候过滤 is_deleted=False
状态用 Integer 而不是 String0/1/2 比 "draft"/"published" 存储更小、查询更快