Files
OnlineJudge/problemset/models.py
2025-10-23 00:54:06 +08:00

230 lines
8.2 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 django.db import models
from django.utils.timezone import now
from account.models import User
from problem.models import Problem
from utils.models import RichTextField, JSONField
class ProblemSet(models.Model):
"""题单模型"""
title = models.TextField(verbose_name="题单标题")
description = RichTextField(verbose_name="题单描述")
# 创建者
created_by = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="创建者"
)
# 创建时间
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
# 更新时间
last_update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
# 是否可见
visible = models.BooleanField(default=True, verbose_name="是否可见")
# 题单难度等级
difficulty = models.TextField(default="Easy", verbose_name="难度等级")
# 题单状态
status = models.TextField(
default="draft", verbose_name="状态"
) # active, archived, draft
class Meta:
db_table = "problemset"
ordering = ("-create_time",)
verbose_name = "题单"
verbose_name_plural = "题单"
def __str__(self):
return self.title
class ProblemSetProblem(models.Model):
"""题单题目关联模型"""
problemset = models.ForeignKey(
ProblemSet, on_delete=models.CASCADE, verbose_name="题单"
)
problem = models.ForeignKey(Problem, on_delete=models.CASCADE, verbose_name="题目")
# 在题单中的顺序
order = models.IntegerField(default=0, verbose_name="顺序")
# 是否为必做题
is_required = models.BooleanField(default=True, verbose_name="是否必做")
# 题目在题单中的分值
score = models.IntegerField(default=0, verbose_name="分值")
# 题目提示信息
hint = models.TextField(null=True, blank=True, verbose_name="提示")
class Meta:
db_table = "problemset_problem"
unique_together = (("problemset", "problem"),)
ordering = ("order",)
verbose_name = "题单题目"
verbose_name_plural = "题单题目"
def __str__(self):
return f"{self.problemset.title} - {self.problem.title}"
class ProblemSetBadge(models.Model):
"""题单奖章模型"""
problemset = models.ForeignKey(
ProblemSet, on_delete=models.CASCADE, verbose_name="题单"
)
name = models.TextField(verbose_name="奖章名称")
description = models.TextField(verbose_name="奖章描述")
# 奖章图标路径
icon = models.TextField(verbose_name="奖章图标")
# 获得条件:完成所有题目、完成指定数量题目、达到指定分数等
condition_type = models.TextField(
verbose_name="获得条件类型"
) # all_problems, problem_count, score
condition_value = models.IntegerField(default=0, verbose_name="条件值")
class Meta:
db_table = "problemset_badge"
verbose_name = "题单奖章"
verbose_name_plural = "题单奖章"
def __str__(self):
return f"{self.problemset.title} - {self.name}"
class ProblemSetProgress(models.Model):
"""题单进度模型"""
problemset = models.ForeignKey(
ProblemSet, on_delete=models.CASCADE, verbose_name="题单"
)
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户")
# 加入时间
join_time = models.DateTimeField(auto_now_add=True, verbose_name="加入时间")
# 完成时间
complete_time = models.DateTimeField(null=True, blank=True, verbose_name="完成时间")
# 是否完成
is_completed = models.BooleanField(default=False, verbose_name="是否完成")
# 完成进度百分比
progress_percentage = models.FloatField(default=0.0, verbose_name="完成进度")
# 已完成的题目数量
completed_problems_count = models.IntegerField(
default=0, verbose_name="已完成题目数"
)
# 总题目数量
total_problems_count = models.IntegerField(default=0, verbose_name="总题目数")
# 获得的总分
total_score = models.IntegerField(default=0, verbose_name="总分")
# 用户在该题单中的详细进度信息
# {"problem_id": {"status": "completed", "score": 100, "submit_time": "2024-01-01T00:00:00Z"}}
progress_detail = JSONField(default=dict, verbose_name="详细进度")
class Meta:
db_table = "problemset_progress"
unique_together = (("problemset", "user"),)
verbose_name = "题单进度"
verbose_name_plural = "题单进度"
def __str__(self):
return f"{self.user.username} - {self.problemset.title}"
def update_progress(self):
"""更新进度信息"""
# 获取题单中的所有题目
problemset_problems = ProblemSetProblem.objects.filter(
problemset=self.problemset
)
self.total_problems_count = problemset_problems.count()
# 计算已完成题目数
completed_count = 0
total_score = 0
for psp in problemset_problems:
problem_id = str(psp.problem.id)
if problem_id in self.progress_detail:
problem_progress = self.progress_detail[problem_id]
if problem_progress.get("status") == "completed":
completed_count += 1
total_score += problem_progress.get("score", 0)
self.completed_problems_count = completed_count
self.total_score = total_score
# 计算完成百分比
if self.total_problems_count > 0:
self.progress_percentage = (
completed_count / self.total_problems_count
) * 100
else:
self.progress_percentage = 0
# 检查是否完成
self.is_completed = completed_count == self.total_problems_count
if self.is_completed and not self.complete_time:
self.complete_time = now()
self.save()
class ProblemSetSubmission(models.Model):
"""题单提交记录模型"""
problemset = models.ForeignKey(
ProblemSet, on_delete=models.CASCADE, verbose_name="题单"
)
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户")
submission = models.ForeignKey(
"submission.Submission", on_delete=models.CASCADE, verbose_name="提交记录"
)
problem = models.ForeignKey(
"problem.Problem", on_delete=models.CASCADE, verbose_name="题目"
)
# 提交时间
submit_time = models.DateTimeField(auto_now_add=True, verbose_name="提交时间")
# 提交结果
result = models.IntegerField(verbose_name="提交结果")
# 得分
score = models.IntegerField(default=0, verbose_name="得分")
# 语言
language = models.CharField(max_length=20, verbose_name="编程语言")
# 代码长度
code_length = models.IntegerField(default=0, verbose_name="代码长度")
# 执行时间(毫秒)
execution_time = models.IntegerField(default=0, verbose_name="执行时间")
# 内存使用KB
memory_usage = models.IntegerField(default=0, verbose_name="内存使用")
class Meta:
db_table = "problemset_submission"
ordering = ("-submit_time",)
verbose_name = "题单提交记录"
verbose_name_plural = "题单提交记录"
indexes = [
models.Index(fields=["problemset", "user"]),
models.Index(fields=["problemset", "problem"]),
models.Index(fields=["user", "submit_time"]),
]
def __str__(self):
return f"{self.user.username} - {self.problemset.title} - {self.problem.title}"
class UserBadge(models.Model):
"""用户奖章模型"""
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户")
badge = models.ForeignKey(
ProblemSetBadge, on_delete=models.CASCADE, verbose_name="奖章"
)
# 获得时间
earned_time = models.DateTimeField(auto_now_add=True, verbose_name="获得时间")
# 是否已展示给用户
is_displayed = models.BooleanField(default=False, verbose_name="是否已展示")
class Meta:
db_table = "user_badge"
unique_together = (("user", "badge"),)
verbose_name = "用户奖章"
verbose_name_plural = "用户奖章"
def __str__(self):
return f"{self.user.username} - {self.badge.name}"