vault backup: 2025-12-26 02:09:22
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m29s
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m29s
This commit is contained in:
22
stroma/quiz/models/__init__.py
Normal file
22
stroma/quiz/models/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from .quiz_user_model import QuizUser
|
||||
from .course_model import Course
|
||||
from .exam_model import Exam
|
||||
from .tag_model import Tag
|
||||
from .question_model import Question
|
||||
from .option_model import Option
|
||||
from .quiz_session_model import QuizSession
|
||||
from .quiz_result_model import QuizResult
|
||||
|
||||
__all__ = [
|
||||
'QuizUser',
|
||||
'Course',
|
||||
'Exam',
|
||||
'Tag',
|
||||
'Question',
|
||||
'Option',
|
||||
'QuizSession',
|
||||
'QuizResult',
|
||||
]
|
||||
|
||||
|
||||
|
||||
12
stroma/quiz/models/course_model.py
Normal file
12
stroma/quiz/models/course_model.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Course(models.Model):
|
||||
name = models.CharField(max_length=200, unique=True)
|
||||
code = models.CharField(max_length=50, blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
18
stroma/quiz/models/exam_model.py
Normal file
18
stroma/quiz/models/exam_model.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from django.db import models
|
||||
from .course_model import Course
|
||||
|
||||
|
||||
class Exam(models.Model):
|
||||
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='exams')
|
||||
date = models.DateField()
|
||||
name = models.CharField(max_length=200, blank=True) # e.g., "2022-01-15"
|
||||
folder_path = models.CharField(max_length=500, blank=True) # Path to exam folder in content
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ['course', 'date']
|
||||
ordering = ['-date']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.course.name} - {self.date}"
|
||||
|
||||
15
stroma/quiz/models/option_model.py
Normal file
15
stroma/quiz/models/option_model.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.db import models
|
||||
from .question_model import Question
|
||||
|
||||
|
||||
class Option(models.Model):
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='options')
|
||||
letter = models.CharField(max_length=1)
|
||||
text = models.TextField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ['question', 'letter']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.letter}. {self.text[:30]}"
|
||||
|
||||
38
stroma/quiz/models/question_model.py
Normal file
38
stroma/quiz/models/question_model.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from django.db import models
|
||||
from .exam_model import Exam
|
||||
from .tag_model import Tag
|
||||
|
||||
|
||||
class Question(models.Model):
|
||||
exam = models.ForeignKey(Exam, on_delete=models.CASCADE, related_name='questions', null=True, blank=True)
|
||||
file_path = models.CharField(max_length=500, unique=True)
|
||||
text = models.TextField()
|
||||
correct_answer = models.CharField(max_length=50) # Support multi-select answers like "A,B,C"
|
||||
file_mtime = models.FloatField(null=True, blank=True) # Track file modification time
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
tags = models.ManyToManyField(Tag, blank=True, related_name='questions')
|
||||
|
||||
# Question type field
|
||||
question_type = models.CharField(
|
||||
max_length=20,
|
||||
default='mcq',
|
||||
choices=[
|
||||
('mcq', 'Multiple Choice'),
|
||||
('scq', 'Single Choice'),
|
||||
('matching', 'Matching'),
|
||||
('textalternativ', 'Text Alternative'),
|
||||
('textfält', 'Text Field'),
|
||||
]
|
||||
)
|
||||
|
||||
# JSON field for matching questions
|
||||
matching_data = models.JSONField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="JSON data for matching questions: {left_items: [...], top_items: [...], correct_pairs: [[0,1], [1,2], ...]}"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.text[:50]
|
||||
|
||||
26
stroma/quiz/models/quiz_result_model.py
Normal file
26
stroma/quiz/models/quiz_result_model.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from django.db import models
|
||||
from .quiz_user_model import QuizUser
|
||||
from .quiz_session_model import QuizSession
|
||||
from .question_model import Question
|
||||
|
||||
|
||||
class QuizResult(models.Model):
|
||||
user = models.ForeignKey(QuizUser, on_delete=models.CASCADE, related_name='results')
|
||||
quiz_session = models.ForeignKey(QuizSession, on_delete=models.CASCADE, related_name='results', null=True, blank=True)
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE)
|
||||
selected_answer = models.CharField(max_length=1)
|
||||
is_correct = models.BooleanField()
|
||||
difficulty = models.CharField(max_length=10, blank=True, null=True, choices=[
|
||||
('again', 'Again'),
|
||||
('hard', 'Hard'),
|
||||
('good', 'Good'),
|
||||
('easy', 'Easy'),
|
||||
])
|
||||
answered_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ['user', 'question']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user} - {self.question.text[:30]} - {'✓' if self.is_correct else '✗'}"
|
||||
|
||||
22
stroma/quiz/models/quiz_session_model.py
Normal file
22
stroma/quiz/models/quiz_session_model.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from django.db import models
|
||||
from .quiz_user_model import QuizUser
|
||||
from .course_model import Course
|
||||
from .exam_model import Exam
|
||||
from .tag_model import Tag
|
||||
|
||||
|
||||
class QuizSession(models.Model):
|
||||
user = models.ForeignKey(QuizUser, on_delete=models.CASCADE, related_name='quiz_sessions')
|
||||
course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
exams = models.ManyToManyField(Exam, blank=True)
|
||||
tags = models.ManyToManyField(Tag, blank=True)
|
||||
question_types = models.JSONField(default=list, blank=True) # Store as list of strings
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"Session {self.id} for {self.user}"
|
||||
|
||||
14
stroma/quiz/models/quiz_user_model.py
Normal file
14
stroma/quiz/models/quiz_user_model.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class QuizUser(models.Model):
|
||||
session_key = models.CharField(max_length=40, unique=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Quiz User"
|
||||
verbose_name_plural = "Quiz Users"
|
||||
|
||||
def __str__(self):
|
||||
return f"User {self.session_key[:8]}"
|
||||
|
||||
10
stroma/quiz/models/tag_model.py
Normal file
10
stroma/quiz/models/tag_model.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=50, unique=True)
|
||||
slug = models.SlugField(max_length=50, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
Reference in New Issue
Block a user