提供基本前后端骨架
This commit is contained in:
141
app/models/user.py
Normal file
141
app/models/user.py
Normal file
@@ -0,0 +1,141 @@
|
||||
"""
|
||||
用户模型
|
||||
|
||||
定义用户数据表结构。
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, String, Text, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.balance import UserBalance
|
||||
|
||||
|
||||
def generate_uuid() -> str:
|
||||
"""生成 UUID 字符串"""
|
||||
return str(uuid4())
|
||||
|
||||
|
||||
def utc_now() -> datetime:
|
||||
"""获取当前 UTC 时间"""
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
class User(Base):
|
||||
"""用户模型"""
|
||||
|
||||
__tablename__ = "users"
|
||||
|
||||
# 主键:使用 UUID 字符串
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=generate_uuid,
|
||||
comment="用户唯一标识",
|
||||
)
|
||||
|
||||
# 账户信息
|
||||
username: Mapped[str] = mapped_column(
|
||||
String(32),
|
||||
unique=True,
|
||||
index=True,
|
||||
nullable=False,
|
||||
comment="用户名",
|
||||
)
|
||||
email: Mapped[str | None] = mapped_column(
|
||||
String(255),
|
||||
unique=True,
|
||||
index=True,
|
||||
nullable=True,
|
||||
comment="邮箱地址",
|
||||
)
|
||||
hashed_password: Mapped[str | None] = mapped_column(
|
||||
String(255),
|
||||
nullable=True, # OAuth2 用户可能没有密码
|
||||
comment="密码哈希",
|
||||
)
|
||||
|
||||
# OAuth2 关联信息
|
||||
oauth_provider: Mapped[str | None] = mapped_column(
|
||||
String(32),
|
||||
nullable=True,
|
||||
index=True,
|
||||
comment="OAuth2 提供商(如 linuxdo)",
|
||||
)
|
||||
oauth_user_id: Mapped[str | None] = mapped_column(
|
||||
String(128),
|
||||
nullable=True,
|
||||
index=True,
|
||||
comment="OAuth2 用户 ID",
|
||||
)
|
||||
|
||||
# 用户状态
|
||||
is_active: Mapped[bool] = mapped_column(
|
||||
Boolean,
|
||||
default=True,
|
||||
nullable=False,
|
||||
comment="是否激活",
|
||||
)
|
||||
is_superuser: Mapped[bool] = mapped_column(
|
||||
Boolean,
|
||||
default=False,
|
||||
nullable=False,
|
||||
comment="是否为超级管理员",
|
||||
)
|
||||
|
||||
# 个人信息
|
||||
nickname: Mapped[str | None] = mapped_column(
|
||||
String(64),
|
||||
nullable=True,
|
||||
comment="昵称",
|
||||
)
|
||||
avatar_url: Mapped[str | None] = mapped_column(
|
||||
String(512),
|
||||
nullable=True,
|
||||
comment="头像 URL",
|
||||
)
|
||||
bio: Mapped[str | None] = mapped_column(
|
||||
Text,
|
||||
nullable=True,
|
||||
comment="个人简介",
|
||||
)
|
||||
|
||||
# 时间戳
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
default=utc_now,
|
||||
server_default=func.now(),
|
||||
nullable=False,
|
||||
comment="创建时间",
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
default=utc_now,
|
||||
onupdate=utc_now,
|
||||
server_default=func.now(),
|
||||
nullable=False,
|
||||
comment="更新时间",
|
||||
)
|
||||
last_login_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
comment="最后登录时间",
|
||||
)
|
||||
|
||||
# 关系
|
||||
balance_account: Mapped["UserBalance | None"] = relationship(
|
||||
"UserBalance",
|
||||
back_populates="user",
|
||||
uselist=False,
|
||||
lazy="selectin",
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<User(id={self.id!r}, username={self.username!r})>"
|
||||
|
||||
Reference in New Issue
Block a user