130 lines
4.4 KiB
Python
130 lines
4.4 KiB
Python
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)."))
|