目 录CONTENT

文章目录

Fastapi数据表定义

~梓
2026-04-11 / 0 评论 / 0 点赞 / 9 阅读 / 0 字
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

User 模型知识点

完整代码

from datetime import datetime
from sqlalchemy import String, DateTime, func, Boolean, Index
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base

class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, comment="主键ID")

    username: Mapped[str] = mapped_column(
        String(50),
        unique=True,
        index=True,
        nullable=False,
        comment="用户名"
    )
    __table_args__ = (
        Index('idx_username_lower', func.lower(username)),
    )

    hashed_password: Mapped[str] = mapped_column(
        String(255),
        nullable=False,
        comment="加密后的密码"
    )

    nickname: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        default="新用户",
        server_default="新用户",
        comment="用户昵称"
    )

    avatar: Mapped[str | None] = mapped_column(
        String(255),
        nullable=True,
        comment="头像URL"
    )

    bio: Mapped[str | None] = mapped_column(
        String(200),
        nullable=True,
        comment="个人简介"
    )

    is_active: Mapped[bool] = mapped_column(
        Boolean,
        default=True,
        server_default="1",
        comment="账户状态: True=正常, False=禁用"
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime,
        server_default=func.now(),
        comment="创建时间"
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime,
        server_default=func.now(),
        onupdate=func.now(),
        comment="最后更新时间"
    )

    # 关联关系
    videos: Mapped[list["Video"]] = relationship(
        back_populates="author",
        cascade="all, delete-orphan",
        lazy="select"
    )

    def __repr__(self) -> str:
        return f"<User(id={self.id}, username={self.username}, nickname={self.nickname})>"

    def __str__(self) -> str:
        return f"User(id={self.id}, username={self.username}, nickname={self.nickname})"

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, User):
            return False
        return self.id == other.id

    def __hash__(self) -> int:
        return hash(self.id)

    @property
    def is_normal(self) -> bool:
        """账户是否正常状态"""
        return self.is_active

    def can_login(self) -> bool:
        """用户是否可以登录"""
        return self.is_active

    def to_dict(self) -> dict:
        """转换为字典格式"""
        return {
            "id": self.id,
            "username": self.username,
            "nickname": self.nickname,
            "avatar": self.avatar,
            "bio": self.bio,
            "is_active": self.is_active,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }


SQLAlchemy 2.0+ 类型注解

from sqlalchemy.orm import Mapped, mapped_column

id: Mapped[int] = mapped_column(primary_key=True)

使用 Mapped 包装类型,mapped_column 定义字段属性

table_args 和 Index

__table_args__ = (
    Index('idx_username_lower', func.lower(username)),
)

表级别的额外配置,用于创建数据库索引。func.lower(username) 生成大小写不敏感的索引表达式

@property 装饰器

把方法伪装成属性,访问时不需要 ()。让代码更简洁自然:

@property
def is_normal(self) -> bool:
    return self.is_active

魔术方法

  • __str__():标准字符串表示,便于调试和日志
  • __eq__(other):比较用户对象,通常用 ID 比较
  • __hash__():支持对象作为字典键
  • __repr__():调试用的对象表示,通常用 <User(...)> 格式

Optional 类型

from typing import Optional
avatar: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)

Python 3.10+ 的 str | None 的旧写法,更明确表达可能为空

关系定义的 lazy 参数

videos: Mapped[list["Video"]] = relationship(
    back_populates="author",
    lazy="select"  # 只查询时才加载
)

控制关联查询时的加载策略,默认是 select(按需加载)

lazy 参数的四种模式

模式 行为 适用场景
select 查询时才加载(默认) 避免 N+1 问题,推荐
joined 使用 JOIN 一次性加载 减少查询次数
subquery 初始化时一次性加载 复杂查询
dynamic 返回 Query 对象,需手动 filter 大量数据

relationship 完整参数解释

```python
videos: Mapped[list["Video"]] = relationship(
    back_populates="author",  # 双向关系
    cascade="all, delete-orphan",  # 级联删除
    lazy="select"  # 懒加载策略
)

back_populates="author" - 双向关系

# User 模型
videos: Mapped[list["Video"]] = relationship(back_populates="author")

# Video 模型
author: Mapped["User"] = relationship(back_populates="videos")

两个模型互相指向对方,确保双向导航:

  • 查询 User 时能拿到 videos
  • 查询 Video 时能拿到 author

cascade="all, delete-orphan" - 级联删除

user = db.get(User, 1)
db.delete(user)  # 删除用户

# 自动删除该用户的所有视频
user.videos  # ['video1', 'video2']
选项 行为
all 所有关联操作都级联
save-update 保存时级联更新
merge 合并时级联
expunge 擦除时级联
delete 删除时级联
delete-orphan 删除孤儿对象(无归属的子对象)
0

评论区