Files
blogweb/backend/models.py
T
2025-12-26 13:42:22 +08:00

145 lines
4.9 KiB
Python

"""
数据库模型定义
使用 SQLModel 定义所有表结构
"""
from datetime import datetime, date
from typing import Optional
from sqlmodel import SQLModel, Field, Relationship, Column
from sqlalchemy import Numeric
from decimal import Decimal
# ==================== 用户表 ====================
class User(SQLModel, table=True):
"""用户表"""
__tablename__ = "users"
id: Optional[int] = Field(default=None, primary_key=True)
username: str = Field(max_length=50, unique=True, index=True)
email: Optional[str] = Field(default=None, max_length=100, unique=True, index=True)
hashed_password: str
created_at: datetime = Field(default_factory=datetime.now)
# ==================== 待办事项表 ====================
class Todo(SQLModel, table=True):
"""待办事项表"""
__tablename__ = "todos"
id: Optional[int] = Field(default=None, primary_key=True)
title: str = Field(max_length=200)
done: bool = Field(default=False)
created_at: datetime = Field(default_factory=datetime.now)
user_id: int = Field(foreign_key="users.id", index=True)
# 关系(可选,用于ORM查询)
user: Optional[User] = Relationship()
# ==================== 博客文章表 ====================
class Post(SQLModel, table=True):
"""博客文章表"""
__tablename__ = "posts"
id: Optional[int] = Field(default=None, primary_key=True)
title: str = Field(max_length=200)
slug: str = Field(max_length=200, index=True)
content: str # 支持 Markdown
created_at: datetime = Field(default_factory=datetime.now)
updated_at: Optional[datetime] = Field(default=None)
user_id: int = Field(foreign_key="users.id", index=True)
# 关系
user: Optional[User] = Relationship()
# ==================== 记账记录表 ====================
class Transaction(SQLModel, table=True):
"""记账记录表"""
__tablename__ = "transactions"
id: Optional[int] = Field(default=None, primary_key=True)
amount: Decimal = Field(sa_column=Column(Numeric(10, 2))) # 正数为收入,负数为支出
category: str = Field(max_length=50)
description: Optional[str] = Field(default=None, max_length=200)
date: date
user_id: int = Field(foreign_key="users.id", index=True)
# 关系
user: Optional[User] = Relationship()
# ==================== 媒体-标签关联表(多对多)====================
class MediaTag(SQLModel, table=True):
"""媒体-标签关联表"""
__tablename__ = "media_tags"
media_id: int = Field(foreign_key="media.id", primary_key=True)
tag_id: int = Field(foreign_key="tags.id", primary_key=True)
# ==================== 书影音收藏表 ====================
class Media(SQLModel, table=True):
"""书影音收藏表"""
__tablename__ = "media"
id: Optional[int] = Field(default=None, primary_key=True)
title: str = Field(max_length=200)
media_type: str = Field(max_length=20) # book / movie / music
rating: Optional[float] = Field(default=None, ge=0.0, le=5.0)
comment: Optional[str] = Field(default=None)
external_id: Optional[str] = Field(default=None, max_length=100) # ISBN、IMDb ID等
cover_url: Optional[str] = Field(default=None, max_length=300)
created_at: datetime = Field(default_factory=datetime.now)
user_id: int = Field(foreign_key="users.id", index=True)
# 关系
user: Optional[User] = Relationship()
tags: list["Tag"] = Relationship(back_populates="media", link_model=MediaTag)
# ==================== 媒体标签表 ====================
class Tag(SQLModel, table=True):
"""媒体标签表"""
__tablename__ = "tags"
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(max_length=50, unique=True, index=True)
# 关系
media: list[Media] = Relationship(back_populates="tags", link_model=MediaTag)
# ==================== 聊天消息表 ====================
class ChatMessage(SQLModel, table=True):
"""聊天消息表"""
__tablename__ = "chat_messages"
id: Optional[int] = Field(default=None, primary_key=True)
content: str
sent_at: datetime = Field(default_factory=datetime.now)
user_id: int = Field(foreign_key="users.id", index=True)
room: str = Field(max_length=50, default="main", index=True)
# 关系
user: Optional[User] = Relationship()
# ==================== 文件上传记录表 ====================
class Upload(SQLModel, table=True):
"""文件上传记录表"""
__tablename__ = "uploads"
id: Optional[int] = Field(default=None, primary_key=True)
filename: str = Field(max_length=200)
stored_path: str = Field(max_length=300)
file_size: int # 字节数
mime_type: str = Field(max_length=100)
uploaded_at: datetime = Field(default_factory=datetime.now)
expires_at: Optional[datetime] = Field(default=None)
user_id: int = Field(foreign_key="users.id", index=True)
# 关系
user: Optional[User] = Relationship()