mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 04:46:26 +00:00
- 移除原监控仪表盘独立模块,将相关功能合并到在线监控模块 - 重构租户配置字段名,统一使用logo_url和name替代tenant_logo/tenant_name - 优化搜索工具函数,移除重复导入 - 调整参数配置模型字段长度限制,移除config_value的max_length约束 - 清理冗余的常量定义和导入语句 - 修复批量状态设置接口的redis依赖注入 - 增强OAuth登录安全性,添加租户默认归属和state一次性消费 - 优化资源目录缓存逻辑,减少重复计算 - 新增API Token模块基础框架 - 完善用户token版本管理,支持主动失效JWT - 调整AI模型配置缓存过期时间 - 修复菜单类型字段索引,提升查询性能 - 简化前端刷新token调用逻辑 - 新增滑块验证完成接口和忘记密码验证码校验 - 调整系统配置默认值,添加操作日志保留天数和接口白名单配置 - 限制Mock支付回调仅在开发环境可用 - 重构websocket认证方式,支持更安全的subprotocol传参
190 lines
5.3 KiB
Python
190 lines
5.3 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String
|
|
from sqlalchemy.ext.asyncio import AsyncAttrs
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, declared_attr, mapped_column, relationship
|
|
|
|
from app.common.enums import PermissionFilterStrategy
|
|
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
|
|
|
|
# 权限过滤策略,子类可以覆盖
|
|
__permission_strategy__: PermissionFilterStrategy = PermissionFilterStrategy.DATA_SCOPE
|
|
|
|
|
|
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",
|
|
index=True,
|
|
)
|
|
uuid: Mapped[str] = mapped_column(
|
|
String(64),
|
|
default=uuid4_str,
|
|
nullable=False,
|
|
unique=True,
|
|
comment="UUID全局唯一标识",
|
|
index=True,
|
|
)
|
|
is_deleted: Mapped[bool] = mapped_column(
|
|
Boolean,
|
|
default=False,
|
|
nullable=False,
|
|
comment="是否已删除(0:未删除 1:已删除)",
|
|
index=True,
|
|
)
|
|
created_time: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
default=datetime.now,
|
|
nullable=False,
|
|
comment="创建时间",
|
|
index=True,
|
|
)
|
|
updated_time: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
default=datetime.now,
|
|
onupdate=datetime.now,
|
|
nullable=False,
|
|
comment="更新时间",
|
|
index=True,
|
|
)
|
|
deleted_time: Mapped[datetime | None] = mapped_column(
|
|
DateTime,
|
|
default=None,
|
|
nullable=True,
|
|
comment="删除时间",
|
|
index=True,
|
|
)
|
|
|
|
|
|
class TenantMixin(MappedBase):
|
|
"""租户隔离字段 Mixin"""
|
|
|
|
__abstract__ = True
|
|
|
|
tenant_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("platform_tenant.id", ondelete="RESTRICT", onupdate="CASCADE"),
|
|
nullable=False,
|
|
default=1,
|
|
index=True,
|
|
comment="租户ID",
|
|
)
|
|
|
|
@declared_attr
|
|
def tenant_by(self):
|
|
"""租户关联关系"""
|
|
return relationship(
|
|
"TenantModel",
|
|
lazy="selectin",
|
|
foreign_keys=lambda: self.tenant_id, # pyright: ignore[reportArgumentType]
|
|
uselist=False,
|
|
)
|
|
|
|
|
|
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",
|
|
)
|
|
|
|
deleted_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(self):
|
|
"""创建人关联关系"""
|
|
return relationship(
|
|
"UserModel",
|
|
lazy="selectin",
|
|
foreign_keys=lambda: self.created_id, # pyright: ignore[reportArgumentType]
|
|
uselist=False,
|
|
)
|
|
|
|
@declared_attr
|
|
def updated_by(self):
|
|
"""更新人关联关系"""
|
|
return relationship(
|
|
"UserModel",
|
|
lazy="selectin",
|
|
foreign_keys=lambda: self.updated_id, # pyright: ignore[reportArgumentType]
|
|
uselist=False,
|
|
)
|
|
|
|
@declared_attr
|
|
def deleted_by(self):
|
|
"""删除人关联关系"""
|
|
return relationship(
|
|
"UserModel",
|
|
lazy="selectin",
|
|
foreign_keys=lambda: self.deleted_id, # pyright: ignore[reportArgumentType]
|
|
uselist=False,
|
|
)
|