fbef15ba7e
- 合并为单一初始全量迁移,覆盖 users/user_devices/user_points/point_batches/point_transactions/point_recharge_orders - 去掉所有 ForeignKey 约束(业务层软删除,不依赖数据库级联) - 去掉不必要的索引,仅保留 Unique 约束自带索引 - 修复 mjk_users.id 为 UUID 类型(非 String(36)) - 修复 user_device.last_active_at 时区类型一致性(添加 timezone=True)
67 lines
1.7 KiB
Python
67 lines
1.7 KiB
Python
"""
|
||
用户设备模型
|
||
============
|
||
|
||
单设备登录约束:一个用户同一时间只能在一个设备上登录。
|
||
user_id 字段带 UNIQUE 约束,强制 1:1 关系。
|
||
"""
|
||
|
||
import uuid
|
||
from datetime import UTC, datetime
|
||
|
||
from sqlalchemy import DateTime, String
|
||
from sqlalchemy.dialects.postgresql import UUID
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.models.base import BaseModelBigInt
|
||
|
||
|
||
class UserDevice(BaseModelBigInt):
|
||
"""用户设备表(单设备登录)"""
|
||
|
||
__tablename__ = "mjk_user_devices"
|
||
|
||
user_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True),
|
||
nullable=False,
|
||
unique=True,
|
||
comment="用户 ID(唯一约束,强制单设备登录)",
|
||
)
|
||
|
||
device_id: Mapped[str] = mapped_column(
|
||
String(64),
|
||
nullable=False,
|
||
comment="设备唯一标识(前端生成)",
|
||
)
|
||
|
||
device_name: Mapped[str | None] = mapped_column(
|
||
String(128),
|
||
nullable=True,
|
||
comment="设备名称(如 'MacBook Pro')",
|
||
)
|
||
|
||
os_info: Mapped[str | None] = mapped_column(
|
||
String(128),
|
||
nullable=True,
|
||
comment="操作系统信息",
|
||
)
|
||
|
||
app_version: Mapped[str | None] = mapped_column(
|
||
String(32),
|
||
nullable=True,
|
||
comment="应用版本号",
|
||
)
|
||
|
||
refresh_token_hash: Mapped[str | None] = mapped_column(
|
||
String(64),
|
||
nullable=True,
|
||
comment="Refresh Token SHA256 哈希(用于校验和撤销)",
|
||
)
|
||
|
||
last_active_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True),
|
||
default=lambda: datetime.now(UTC),
|
||
nullable=False,
|
||
comment="最后活跃时间",
|
||
)
|