Files
----/后端源码/yifan.action-ai.cn/app/core/base_model.py

119 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
from typing import Optional
from datetime import datetime
from sqlalchemy import DateTime, String, Integer, Text, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase, declared_attr, relationship
from sqlalchemy.ext.asyncio import AsyncAttrs
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from app.api.v1.module_system.user.model import UserModel
from app.utils.common_util import uuid4_str
class MappedBase(AsyncAttrs, DeclarativeBase):
"""
声明式基类
`AsyncAttrs <https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html#sqlalchemy.ext.asyncio.AsyncAttrs>`__
`DeclarativeBase <https://docs.sqlalchemy.org/en/20/orm/declarative_config.html>`__
`mapped_column() <https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.mapped_column>`__
兼容 SQLite、MySQL 和 PostgreSQL
"""
__abstract__: bool = True
class ModelMixin(MappedBase):
"""
模型混入类 - 提供通用字段和功能
基础模型混合类 Mixin: 一种面向对象编程概念, 使结构变得更加清晰
数据隔离设计原则:
==================
数据权限 (created_id/updated_id):
- 配合角色的data_scope字段实现精细化权限控制
- 1:仅本人
- 2:本部门
- 3:本部门及以下
- 4:全部数据
- 5:自定义
SQLAlchemy加载策略说明:
- select(默认): 延迟加载,访问时单独查询
- joined: 使用LEFT JOIN预加载
- selectin: 使用IN查询批量预加载(推荐用于一对多)
- subquery: 使用子查询预加载
- raise/raise_on_sql: 禁止加载
- noload: 不加载,返回None
- immediate: 立即加载
- write_only: 只写不读
- dynamic: 返回查询对象,支持进一步过滤
"""
__abstract__: bool = True
# 基础字段
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
uuid: Mapped[str] = mapped_column(String(64), default=uuid4_str, nullable=False, unique=True, comment='UUID全局唯一标识')
status: Mapped[str] = mapped_column(String(10), default='0', nullable=False, comment="是否启用(0:启用 1:禁用)")
description: Mapped[str | None] = mapped_column(Text, default=None, nullable=True, comment="备注/描述")
created_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now, nullable=False, comment='创建时间')
updated_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now, onupdate=datetime.now, nullable=False, comment='更新时间')
class UserMixin(MappedBase):
"""
用户审计字段 Mixin
用于记录数据的创建者和更新者
用于实现数据权限中的"仅本人数据权限"
"""
__abstract__: bool = True
created_id: Mapped[int | None] = mapped_column(
Integer,
ForeignKey('sys_user.id', ondelete="SET NULL", onupdate="CASCADE"),
default=None,
nullable=True,
index=True,
comment="创建人ID"
)
updated_id: Mapped[int | None] = mapped_column(
Integer,
ForeignKey('sys_user.id', ondelete="SET NULL", onupdate="CASCADE"),
default=None,
nullable=True,
index=True,
comment="更新人ID"
)
@declared_attr
def created_by(cls) -> Mapped[Optional["UserModel"]]:
"""
创建人关联关系(延迟加载,避免循环依赖)
"""
return relationship(
"UserModel",
lazy="selectin",
foreign_keys=lambda: cls.created_id,
uselist=False
)
@declared_attr
def updated_by(cls) -> Mapped[Optional["UserModel"]]:
"""
更新人关联关系(延迟加载,避免循环依赖)
"""
return relationship(
"UserModel",
lazy="selectin",
foreign_keys=lambda: cls.updated_id,
uselist=False
)