Add command to generate sample physics questions with customizable options
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import transaction
|
||||
import random
|
||||
|
||||
from physics.models import Question, Category, Exam
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Generate a number of sample physics questions for development/testing."
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--count",
|
||||
type=int,
|
||||
default=10,
|
||||
help="Number of sample questions to create (default: 10)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--category",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Category name to assign to created questions (created if missing)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--author",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Username of an existing user to add as author for created questions",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--seed",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Optional random seed for reproducible generation",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--create-exam",
|
||||
dest="create_exam",
|
||||
type=str,
|
||||
default=None,
|
||||
help="If provided, create an exam with this name and add generated questions to it",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--activate",
|
||||
action="store_true",
|
||||
dest="activate",
|
||||
help="If set when creating an exam, mark the exam active",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
count = options.get("count") or 10
|
||||
category_name = options.get("category")
|
||||
author_username = options.get("author")
|
||||
seed = options.get("seed")
|
||||
|
||||
if seed is not None:
|
||||
random.seed(seed)
|
||||
|
||||
category = None
|
||||
if category_name:
|
||||
category, _ = Category.objects.get_or_create(category=category_name)
|
||||
|
||||
created_exam = None
|
||||
create_exam_name = options.get("create_exam")
|
||||
activate = options.get("activate")
|
||||
if create_exam_name:
|
||||
created_exam = Exam.objects.create(name=create_exam_name, active=bool(activate))
|
||||
|
||||
author_user = None
|
||||
if author_username:
|
||||
try:
|
||||
author_user = User.objects.get(username=author_username)
|
||||
except User.DoesNotExist:
|
||||
self.stdout.write(self.style.WARNING(f"Author username '{author_username}' not found; continuing without author"))
|
||||
author_user = None
|
||||
|
||||
created = 0
|
||||
|
||||
with transaction.atomic():
|
||||
for i in range(count):
|
||||
qnum = Question.objects.count() + 1
|
||||
stem = f"Sample physics question #{qnum}: Identify which of the following statements are true."
|
||||
|
||||
# simple option texts
|
||||
opts = [
|
||||
f"Statement A for question {qnum}",
|
||||
f"Statement B for question {qnum}",
|
||||
f"Statement C for question {qnum}",
|
||||
f"Statement D for question {qnum}",
|
||||
f"Statement E for question {qnum}",
|
||||
]
|
||||
|
||||
# randomly decide true/false for each option but ensure at least one True
|
||||
answers = [random.choice([True, False]) for _ in range(5)]
|
||||
if not any(answers):
|
||||
answers[random.randrange(5)] = True
|
||||
|
||||
q = Question.objects.create(
|
||||
stem=stem,
|
||||
a=opts[0],
|
||||
a_answer=answers[0],
|
||||
a_feedback="",
|
||||
b=opts[1],
|
||||
b_answer=answers[1],
|
||||
b_feedback="",
|
||||
c=opts[2],
|
||||
c_answer=answers[2],
|
||||
c_feedback="",
|
||||
d=opts[3],
|
||||
d_answer=answers[3],
|
||||
d_feedback="",
|
||||
e=opts[4],
|
||||
e_answer=answers[4],
|
||||
e_feedback="",
|
||||
category=category,
|
||||
)
|
||||
|
||||
# If we created an exam, add this question to it
|
||||
if created_exam:
|
||||
created_exam.exam_questions.add(q)
|
||||
if author_user:
|
||||
q.author.add(author_user)
|
||||
|
||||
created += 1
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"Created {created} sample physics question(s)."))
|
||||
Reference in New Issue
Block a user