Hi all,
I am experiencing an issue when using the RecursiveField. I am creating questionnaires. To create sections in the questionnaire, you can recursively add questionnaire items to existing questionnaire items. The questionnaire is well created into the DB but when it is returning the response, there is no item key for the nested questionnaire items. Do you have an idea? (Thanks for your help)
django RF= 3.7.3
python=2.7.10
Those are my models:
class Questionnaire(models.Model):
rowId = models.BigAutoField(primary_key=True, editable=False, db_column="rowId")
id = models.UUIDField(unique=True, default=uuid4, editable=False, db_column="id")
owner = models.ForeignKey('oauth.Application', related_name='Questionnaire', on_delete=models.CASCADE, db_column="ownerId")
url = models.CharField(max_length=250, null=True, db_column="url")
title = models.CharField(max_length=200, null=True, db_column="title")
status = models.CharField(max_length=3, choices=STATUS_CHOICES, default=UNKNOWN, db_column="status")
date = models.DateField(auto_now=True, null=False, db_column="date")
publisher = models.CharField(max_length=200, null=True, db_column="publisher")
description = models.CharField(max_length=400, null=True, db_column="description")
purpose = models.CharField(max_length=400, null=True, db_column="purpose")
# item
# Reverse foreign key ---> QuestionnaireItem
class Meta:
db_table = "questionnaire"
class QuestionnaireItem(models.Model):
id = models.BigAutoField(primary_key=True, editable=False, db_column="id")
questionnaire = models.ForeignKey("api.Questionnaire",
db_index=True,
null=True,
on_delete=models.PROTECT,
to_field='id',
related_name='item',
db_column="questionnaireId")
text = models.CharField(max_length=400, null=True, db_column="text")
type = models.CharField(max_length=4, choices=TYPE_CHOICES, default=UNKNOWN, db_column="type")
required = models.NullBooleanField(null=True, db_column="required")
readOnly = models.NullBooleanField(null=True, db_column="readOnly")
maxLength = models.PositiveIntegerField(null=True, db_column="maxLength")
# option
# Reverse foreign key ---> QuestionnaireOption
initialBoolean = models.NullBooleanField(null=True, db_column="initialBoolean")
initialDecimal = models.DecimalField(null=True, db_column="initialDecimal", max_digits=10, decimal_places=2)
initialInteger = models.IntegerField(null=True, db_column="initialInteger")
initialDate = models.DateField(null=True, db_column="initialDate")
initialString = models.CharField(max_length=400, null=True, db_column="initialString")
initialUri = models.CharField(max_length=200, null=True, db_column="initialUri")
initialAttachment = models.OneToOneField("api.Attachment", null=True, on_delete=models.PROTECT, related_name="initialAttachment", db_column="initialAttachmentId")
initialQuantity = models.OneToOneField("api.Quantity", null=True, on_delete=models.PROTECT, related_name="initialQuantity", db_column="initialQuantityId")
# item
# Allow to create sections and sub-sections
# Reverse foreign key ---> QuestionnaireItem
item = models.ForeignKey('self',
db_index=True,
on_delete=models.PROTECT,
null=True,
related_name='sub_item',
db_column="questionnaireItemId")
class Meta:
db_table = "questionnaire_item"
class QuestionnaireOption(models.Model):
id = models.BigAutoField(primary_key=True, editable=False, db_column="id")
questionnaireItem = models.ForeignKey("api.QuestionnaireItem",
db_index=True,
on_delete=models.PROTECT,
null=True,
to_field='id',
related_name='option',
db_column="questionnaireItemId")
valueInteger = models.IntegerField(null=True, db_column="valueInteger")
valueDate = models.DateField(null=True, db_column="valueDate")
valueString = models.CharField(max_length=200, null=True, db_column="valueUri")
class Meta:
db_table = "questionnaire_option"
Those are my serializers:
class QuestionnaireOptionSerializer(serializers.ModelSerializer):
valueInteger = serializers.IntegerField(required=False)
valueDate = serializers.DateField(required=False)
valueString = serializers.CharField(required=False)
class Meta:
model = QuestionnaireItem
fields = ('valueInteger', 'valueDate', 'valueString')
def to_representation(self, instance):
result = super(QuestionnaireOptionSerializer, self).to_representation(instance)
return OrderedDict([(key, result[key]) for key in result if result[key] is not None])
class QuestionnaireItemSerializer(serializers.ModelSerializer):
text = serializers.CharField(required=True)
type = CustomChoiceField(choices=TYPE_CHOICES, required=True)
required = serializers.CharField(required=False)
readOnly = serializers.CharField(required=False)
maxLength = serializers.IntegerField(required=False)
option = QuestionnaireOptionSerializer(many=True, required=False)
initialBoolean = serializers.BooleanField(required=False)
initialDecimal = serializers.DecimalField(required=False, max_digits=10, decimal_places=2)
initialInteger = serializers.IntegerField(required=False)
initialDate = serializers.DateField(required=False)
initialString = serializers.CharField(required=False)
initialUri = serializers.CharField(required=False)
initialAttachment = AttachmentSerializer(many=False, required=False)
initialQuantity = QuantitySerializer(many=False, required=False)
item = serializers.ListField(child=RecursiveField(), required=False)
class Meta:
model = QuestionnaireItem
managed = True
fields = ('text', 'type', 'required', 'readOnly', 'maxLength', 'option', 'initialBoolean', 'initialDecimal', 'initialInteger', 'initialDate', 'initialString', 'initialUri', 'initialAttachment', 'initialQuantity', 'item')
def to_representation(self, instance):
result = super(QuestionnaireItemSerializer, self).to_representation(instance)
return OrderedDict([(key, result[key]) for key in result if result[key] is not None])
class QuestionnaireSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(read_only=True)
url = serializers.CharField(required=False)
title = serializers.CharField(required=True)
status = CustomChoiceField(choices=STATUS_CHOICES, required=False)
date = serializers.DateField(required=False)
publisher = serializers.CharField(required=False)
description = serializers.CharField(required=False)
purpose = serializers.CharField(required=False)
item = QuestionnaireItemSerializer(many=True, required=True)
def create(self, validated_data):
print(validated_data)
# Get the linked application
application = get_app_by_access_token(self.context)
# Dealing with the nested structure
questionnaire_item_data = validated_data.pop('item')
# Saving the questionnaire
questionnaire = Questionnaire.objects.create(owner=application, **validated_data)
# Saving first level
for item in questionnaire_item_data:
should_add_option = False
should_add_item = False
if 'option' in item:
questionnaire_option_data = item.pop('option')
should_add_option = True
if 'item' in item:
sub_item_data = item.pop('item')
should_add_item = True
# Saving the questionnaire item
questionnaireItem = QuestionnaireItem.objects.create(questionnaire=questionnaire, **item)
if should_add_option:
# Saving second level
for option in questionnaire_option_data:
# Saving the questionnaire options
QuestionnaireOption.objects.create(questionnaireItem=questionnaireItem, **option)
if should_add_item:
# Saving second level
for sub_item in sub_item_data:
# Saving the questionnaire sub item
QuestionnaireItem.objects.create(questionnaire=questionnaire, item=questionnaireItem, **sub_item)
# Return
return questionnaire
class Meta:
model = Questionnaire
fields = ('id', 'url', 'title', 'status', 'date', 'publisher', 'description', 'purpose', 'item')
def to_representation(self, instance):
result = super(QuestionnaireSerializer, self).to_representation(instance)
return OrderedDict([(key, result[key]) for key in result if result[key] is not None])