django abstract base class with ManyToMany

Viewed 261
class Question(models.Model):
    answer_choices = models.ManyToManyField(Answers)

    class Meta:
        abstract = True

class HTMLQuestion(Question):
    question = models.fields.TextField()

class TextQuestion(Question):
    question = models.fields.TextField()

class Quiz(models.Model):
    questions = models.ManyToManyField(Question)

The last line doesn't work. I can't run python manage.py makemigrations without the error "Field defines a relation with model 'Question', which is either not installed, or is abstract."

Is there a way to have a list of Question subclassed instances without having it be of type "Question"? I want to have both types HTMLQuestion and TextQuestions to be in the Quiz.

3 Answers

The answer I ended up with was to forget working with inheritance in Django and instead to put the type in the Question and then created functions of how to deal with that type in the Question model itself.

class Question(models.Model):
    answer_choices = models.ManyToManyField(Answers)
    question_type = models.fields.TextField() # "htmlquestion", "textquestion"
    
    def how_to_deal_with_type(question_type):
        # code here

class Quiz(models.Model):
    questions = models.ManyToManyField(Question)

when you define the Question model as abstract it does not create a table during migration. An abstract model allows you to reuse implementation/fields, but not relations. The ManyToMany field and the ForeignKey field require a table to refer to. In your case you need to handle the many-to-many relation manually by creating a support table similar to the one django creates for you when you use the ManyToMany field. In your particular case it should have four columns:

  • id(auto),
  • quiz(foreign_key),
  • q_type(if for each type you derived from question),
  • q_id(integer that holds the id of the record you are referring).

use the q_type to get the concrete model where you will get the q_id.

Related