Add management commands for creating anatomy questions with customizable options

This commit is contained in:
Ross
2025-11-10 22:24:44 +00:00
parent 44ca49899a
commit e39539fb99
3 changed files with 130 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
"""Management package for anatomy app."""
+1
View File
@@ -0,0 +1 @@
"""Management commands package for anatomy app."""
@@ -0,0 +1,128 @@
from __future__ import annotations
import os
from uuid import uuid4
from typing import List
from django.core.management.base import BaseCommand, CommandError
from django.core.files import File
from django.contrib.auth import get_user_model
from anatomy.models import AnatomyQuestion, Exam, ExamQuestionDetail, QuestionType, Modality, Structure
from generic.models import Modality as GenericModality # type: ignore
class Command(BaseCommand):
help = (
"Create anatomy questions and assign them to an exam."
"Requires --exam-id and --image-path (path readable inside the container)."
)
def add_arguments(self, parser):
parser.add_argument("--exam-id", type=int, required=True, help="ID of the anatomy.Exam to assign questions to")
parser.add_argument("--count", type=int, default=1, help="Number of questions to create")
parser.add_argument("--image-path", type=str, required=True, help="Path to image file to use for each created question")
parser.add_argument("--description", type=str, default="Generated question {i}", help="Description template; use {i} for index")
parser.add_argument("--question-type-id", type=int, default=None, help="Optional QuestionType id to assign")
parser.add_argument("--modality-id", type=int, default=None, help="Optional Modality id to assign (generic.Modality id)")
parser.add_argument("--structure-id", type=int, default=None, help="Optional Structure id to assign")
parser.add_argument("--author-id", type=int, action="append", help="Author user id; repeatable")
parser.add_argument("--start-sort", type=int, default=1, help="Starting sort_order for the first question")
def handle(self, *args, **options):
exam_id = options["exam_id"]
count = options["count"]
image_path = options["image_path"]
description_template = options["description"]
qtype_id = options.get("question_type_id")
modality_id = options.get("modality_id")
structure_id = options.get("structure_id")
author_ids: List[int] = options.get("author_id") or []
sort = options.get("start_sort") or 1
try:
exam = Exam.objects.get(pk=exam_id)
except Exam.DoesNotExist:
raise CommandError(f"Exam with id {exam_id} does not exist")
if not os.path.exists(image_path):
raise CommandError(f"Image file not found at path: {image_path}")
# Resolve optional foreign keys
qtype = None
if qtype_id:
qtype = QuestionType.objects.filter(pk=qtype_id).first()
if not qtype:
raise CommandError(f"QuestionType id {qtype_id} not found")
modality = None
if modality_id:
# The project stores Modality in generic.models.Modality
try:
from generic.models import Modality as GModality
modality = GModality.objects.filter(pk=modality_id).first()
if not modality:
raise CommandError(f"Modality id {modality_id} not found in generic.Modality")
except Exception as e:
raise CommandError(str(e))
structure = None
if structure_id:
from atlas.models import Structure as AtlasStructure
structure = AtlasStructure.objects.filter(pk=structure_id).first()
if not structure:
raise CommandError(f"Structure id {structure_id} not found")
User = get_user_model()
authors = []
for uid in author_ids:
u = User.objects.filter(pk=uid).first()
if not u:
raise CommandError(f"Author user id {uid} not found")
authors.append(u)
created = []
for i in range(1, count + 1):
desc = description_template.format(i=i)
# Prepare a unique filename to avoid collisions
basename = os.path.basename(image_path)
unique_name = f"{uuid4().hex}_{basename}"
with open(image_path, "rb") as f:
django_file = File(f, name=unique_name)
q = AnatomyQuestion(
question_type=qtype,
description=desc,
answer_help="",
)
if modality:
q.modality = modality
if structure:
q.structure = structure
# Assign image then save
q.image.save(unique_name, django_file, save=False)
q.save()
# authors
if authors:
q.author.set(authors)
# add to exam via the many-to-many through relationship
# use through_defaults for sort_order when possible
try:
exam.exam_questions.add(q, through_defaults={"sort_order": sort})
except TypeError:
# older Django or in case add doesn't support through_defaults, create through model
ExamQuestionDetail.objects.create(exam=exam, anatomyquestion=q, sort_order=sort)
self.stdout.write(self.style.SUCCESS(f"Created question id={q.id} and added to exam id={exam.id} with sort_order={sort}"))
created.append(q)
sort += 1
self.stdout.write(self.style.SUCCESS(f"Finished: created {len(created)} question(s)"))