Home > Software engineering >  Queryset for specific child class (NOT abstract model)
Queryset for specific child class (NOT abstract model)

Time:02-04

How do I get a queryset of specific child classes? It doesn't look like going through related_name is the answer. Using Django 3.2.6 btw.

Here is my setup:

class Quiz(models.Model):
    name = # char field

class Question(models.Model):
    # a quiz has many questions
    quiz = models.ForeignKey(Quiz, related_name = '%(class)s')
    # etc...

class TFQuestion(Question):
    is_true = models.BooleanField(...)

class MCQuestion(Question):
    n_choices = models.IntegerField(...)

What I want is to get a queryset of just MC Questions and process them as such.

I feel the need to emphasize that Question is NOT abstract. So the question model has its own related_name but the specified '%(class)s' pattern does not seem to propagate down to the child classes. All the other threads I've seen suggest using that pattern but it only works for abstract models! not when using multi-table inheritance.

From what I've seen, I can't just do:

quiz1 = Quiz.objects.get(id=1)

# this works; returns queryset of Question objects
allquestions = quiz1.question.all()

# doesn't work
all_mcqs = quiz1.mcquestion.all()

CodePudding user response:

You can .filter(…) [Django-doc] with:

MCQuestion.objects.filter(quiz=quiz1)

For inheritance of a concrete model, Django will make tables for the Question, TFQuestion and MCQuestions, so three tables. The MCQuestion will have a "hidden" OneToOneField to Question.

CodePudding user response:

self answer (kinda)

a couple workarounds i've seen, but jankier than just using a related_name:

A.) using classname__isnull:


quiz1 = Quiz.objects.get(id=1)

# get quiz1's MCQuestions as Questions
qs1 = quiz1.question.filter(mcquestion__isnull = False)
# returns: <QuerySet[<Question>,...]>
qs1.first().mcquestion.n_choices

B.) using InheritanceManager and classname__isnull:

from model_utils.managers import InheritanceManager

class Question(models.Model):
    # ...
    objects = InheritanceManager()

# django shell

quiz1 = Quiz.objects.get(id=1)

# get quiz1's MCQuestions as MCQuestions
qs1 = quiz1.question.select_subclasses().filter(mcquestion__isnull = False)
# returns: <InheritanceQuerySet[<Question>,...]>
qs1.first().n_choices
  • Related