I'm trying to build two abstract classes called SurveyQuestionBase
and SurveyResponseBase
that will serve as templates to quickly define new concrete Models for implementing specific surveys on our website. The issue I am having is in enforcing that the SurveyResponseBase
model, when made concrete, should define a ForeignKey
to a concrete model of SurveyQuestionBase
.
Django does not allow us to define ForeignKeys
to abstract classes so I cannot, for instance, do this:
question = models.ForeignKey(SurveyQuestionBase)
Neither can I have it as None
or app_label.ModelName
for similar reasons.
One hacky fix is to create a new concrete model SurveyQuestionConcrete
and make the ForeignKey
point to this: question = models.ForeignKey(concrete_model)
, combined with validation to ensure this model is replaced.
Is there a cleaner way to achieve the same thing? All I need to do is ensure that when someone defines a concrete model from SurveyResponseBase
they include a ForeignKey
to a concrete model defined from SurveyQuestionBase
Here's the full code:
from __future__ import unicode_literals
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
# Implementation borrows from: https://github.com/jessykate/django-survey/
class SurveyQuestionBase(models.Model):
TEXT = 'text'
INTEGER = 'integer'
RADIO = 'radio'
SELECT = 'select'
MULTI_SELECT = 'multi-select'
ANSWER_TYPE_CHOICES = (
(INTEGER, 'Integer',),
(TEXT, 'Text',),
(RADIO, 'Radio',),
(SELECT, 'Select',),
(MULTI_SELECT, 'Multi-Select',),
)
question = models.TextField()
required = models.BooleanField()
question_type = models.CharField(choices=ANSWER_TYPE_CHOICES, max_length=20)
class Meta:
abstract = True
class SurveyResponseBase(models.Model):
"""
concrete_question_model: 'app_label.Model' - Define the concrete model this question belongs to
"""
concrete_model = 'SurveyQuestionBase'
question = models.ForeignKey(concrete_model)
response = models.TextField()
class Meta:
abstract = True