Files
012-kaopeilian/backend/app/models/exam.py
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

154 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
考试相关模型定义
"""
from datetime import datetime
from typing import List, Optional
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, JSON, Float, func
from sqlalchemy.orm import relationship, Mapped, mapped_column
from app.models.base import BaseModel
class Exam(BaseModel):
"""考试记录模型"""
__tablename__ = "exams"
__allow_unmapped__ = True
id: Mapped[int] = mapped_column(Integer, primary_key=True)
user_id: Mapped[int] = mapped_column(
Integer, ForeignKey("users.id"), nullable=False, index=True
)
course_id: Mapped[int] = mapped_column(
Integer, ForeignKey("courses.id"), nullable=False, index=True
)
# 考试信息
exam_name: Mapped[str] = mapped_column(String(255), nullable=False)
question_count: Mapped[int] = mapped_column(Integer, default=10)
total_score: Mapped[float] = mapped_column(Float, default=100.0)
pass_score: Mapped[float] = mapped_column(Float, default=60.0)
# 考试时间
start_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), comment="开始时间(北京时间)")
end_time: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True, comment="结束时间(北京时间)")
duration_minutes: Mapped[int] = mapped_column(Integer, default=60) # 考试时长(分钟)
# 考试结果
score: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
# 三轮考试得分
round1_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True, comment="第一轮得分")
round2_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True, comment="第二轮得分")
round3_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True, comment="第三轮得分")
is_passed: Mapped[Optional[bool]] = mapped_column(nullable=True)
# 考试状态: started, submitted, timeout
status: Mapped[str] = mapped_column(String(20), default="started", index=True)
# 考试数据JSON格式存储题目和答案
questions: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
answers: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
# 关系
user = relationship("User", back_populates="exams")
course = relationship("Course", back_populates="exams")
results = relationship("ExamResult", back_populates="exam")
def __repr__(self):
return f"<Exam(id={self.id}, user_id={self.user_id}, course_id={self.course_id}, status={self.status})>"
class Question(BaseModel):
"""题目模型"""
__tablename__ = "questions"
__allow_unmapped__ = True
id: Mapped[int] = mapped_column(Integer, primary_key=True)
course_id: Mapped[int] = mapped_column(
Integer, ForeignKey("courses.id"), nullable=False, index=True
)
# 题目类型: single_choice, multiple_choice, true_false, fill_blank, essay
question_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True)
# 题目内容
title: Mapped[str] = mapped_column(Text, nullable=False)
content: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
# 选项JSON格式适用于选择题
options: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
# 答案
correct_answer: Mapped[str] = mapped_column(Text, nullable=False)
explanation: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
# 分值
score: Mapped[float] = mapped_column(Float, default=10.0)
# 难度等级: easy, medium, hard
difficulty: Mapped[str] = mapped_column(String(10), default="medium", index=True)
# 标签JSON格式
tags: Mapped[Optional[list]] = mapped_column(JSON, nullable=True)
# 使用统计
usage_count: Mapped[int] = mapped_column(Integer, default=0)
correct_count: Mapped[int] = mapped_column(Integer, default=0)
# 状态
is_active: Mapped[bool] = mapped_column(default=True, index=True)
# 关系
course = relationship("Course", back_populates="questions")
def __repr__(self):
return f"<Question(id={self.id}, course_id={self.course_id}, type={self.question_type})>"
class ExamResult(BaseModel):
"""考试结果详情模型"""
__tablename__ = "exam_results"
__allow_unmapped__ = True
id: Mapped[int] = mapped_column(Integer, primary_key=True)
exam_id: Mapped[int] = mapped_column(
Integer, ForeignKey("exams.id"), nullable=False, index=True
)
question_id: Mapped[int] = mapped_column(
Integer, ForeignKey("questions.id"), nullable=False
)
# 用户答案
user_answer: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
# 是否正确
is_correct: Mapped[bool] = mapped_column(default=False)
# 得分
score: Mapped[float] = mapped_column(Float, default=0.0)
# 答题时长(秒)
answer_time: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
# 关系
exam = relationship("Exam", back_populates="results")
question = relationship("Question")
def __repr__(self):
return f"<ExamResult(id={self.id}, exam_id={self.exam_id}, question_id={self.question_id}, is_correct={self.is_correct})>"
# 在模型文件末尾添加关系定义
# 需要在User模型中添加
# exams = relationship("Exam", back_populates="user")
# 需要在Course模型中添加
# exams = relationship("Exam", back_populates="course")
# questions = relationship("Question", back_populates="course")
# 需要在Exam模型中添加
# results = relationship("ExamResult", back_populates="exam")