Files
problem-bank/backend/models.py

121 lines
5.0 KiB
Python
Raw Normal View History

2026-03-05 11:50:15 +08:00
from datetime import datetime
2026-03-06 15:52:34 +08:00
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
2026-03-05 11:50:15 +08:00
from sqlalchemy.orm import Mapped, mapped_column, relationship
from backend.database import Base
2026-03-06 15:52:34 +08:00
# 导入任务/文件项统一状态
JOB_STATUS_QUEUED = "queued"
JOB_STATUS_RUNNING = "running"
JOB_STATUS_SUCCESS = "success"
JOB_STATUS_FAILED = "failed"
JOB_STATUS_CANCELLED = "cancelled"
JOB_STATUS_RETRYING = "retrying"
JOB_STATUSES = (
JOB_STATUS_QUEUED,
JOB_STATUS_RUNNING,
JOB_STATUS_SUCCESS,
JOB_STATUS_FAILED,
JOB_STATUS_CANCELLED,
JOB_STATUS_RETRYING,
)
2026-03-05 11:50:15 +08:00
class Question(Base):
__tablename__ = "questions"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
chapter: Mapped[str] = mapped_column(Text, default="")
primary_knowledge: Mapped[str] = mapped_column(Text, default="")
secondary_knowledge: Mapped[str] = mapped_column(Text, default="")
question_type: Mapped[str] = mapped_column(Text, default="")
difficulty: Mapped[str] = mapped_column(Text, default="")
stem: Mapped[str] = mapped_column(Text)
option_a: Mapped[str] = mapped_column(Text, default="")
option_b: Mapped[str] = mapped_column(Text, default="")
option_c: Mapped[str] = mapped_column(Text, default="")
option_d: Mapped[str] = mapped_column(Text, default="")
answer: Mapped[str] = mapped_column(Text, default="")
explanation: Mapped[str] = mapped_column(Text, default="")
notes: Mapped[str] = mapped_column(Text, default="")
source_file: Mapped[str] = mapped_column(Text, default="")
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
class Category(Base):
__tablename__ = "categories"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(Text, nullable=False)
parent_id: Mapped[int | None] = mapped_column(ForeignKey("categories.id"), nullable=True)
level: Mapped[int] = mapped_column(Integer, default=1)
children: Mapped[list["Category"]] = relationship(
"Category", backref="parent", remote_side=[id], lazy="joined"
)
class ImportHistory(Base):
__tablename__ = "import_history"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
filename: Mapped[str] = mapped_column(Text, default="")
method: Mapped[str] = mapped_column(Text, default="manual")
question_count: Mapped[int] = mapped_column(Integer, default=0)
status: Mapped[str] = mapped_column(Text, default="success")
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
2026-03-06 15:52:34 +08:00
class ImportJob(Base):
"""导入任务(持久化队列项)。"""
__tablename__ = "import_jobs"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
status: Mapped[str] = mapped_column(String(32), default=JOB_STATUS_QUEUED, index=True)
method: Mapped[str] = mapped_column(String(32), nullable=False)
total: Mapped[int] = mapped_column(Integer, default=0)
processed: Mapped[int] = mapped_column(Integer, default=0)
success_count: Mapped[int] = mapped_column(Integer, default=0)
failed_count: Mapped[int] = mapped_column(Integer, default=0)
current_index: Mapped[int] = mapped_column(Integer, default=0)
current_file: Mapped[str] = mapped_column(Text, default="")
error: Mapped[str] = mapped_column(Text, default="")
attempt: Mapped[int] = mapped_column(Integer, default=1)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
ended_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
items: Mapped[list["ImportJobItem"]] = relationship(
"ImportJobItem", back_populates="job", order_by="ImportJobItem.seq", lazy="selectin"
)
class ImportJobItem(Base):
"""导入任务内的单个文件项。"""
__tablename__ = "import_job_items"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
job_id: Mapped[int] = mapped_column(ForeignKey("import_jobs.id", ondelete="CASCADE"), nullable=False)
seq: Mapped[int] = mapped_column(Integer, nullable=False)
filename: Mapped[str] = mapped_column(Text, default="")
stored_path: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(32), default=JOB_STATUS_QUEUED)
attempt: Mapped[int] = mapped_column(Integer, default=1)
error: Mapped[str] = mapped_column(Text, default="")
question_count: Mapped[int] = mapped_column(Integer, default=0)
started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
ended_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
job: Mapped["ImportJob"] = relationship("ImportJob", back_populates="items")