Dkova
Dkova

Reputation: 1097

Django post list json

I'm trying to send a list in JSON with more parameters. All the parameters works but not the list, which is saved as an empty list. I'm using Django REST Framework and a nested serializer.

This is my serializers.py

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ('tagID', 'tagName')

class IncentiveSerializer(serializers.ModelSerializer):
    tags=TagSerializer(many=True,read_only=True)
    class Meta:
        model = Incentive
        fields = ('schemeName', 'schemeID','text','typeID','typeName','status','ordinal','tags','modeID',
        'groupIncentive','condition')

This is my models.py

class Incentive(models.Model):
    highlighted = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    ... more fields ....
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    #email = models.TextField()

    class Meta:
        ordering = ('created',)

    def save(self, *args, **kwargs):
        """
        Use the `pygments` library to create a highlighted HTML
        representation of the code snippet.
        """
        lexer = get_lexer_by_name(self.language)
        options = self.schemeName and {'title': self.schemeName} or {}
        formatter = HtmlFormatter(text=self.text,
                              full=True, **options)
        self.highlighted = highlight(self.schemeName, lexer, formatter)
        super(Incentive, self).save(*args, **kwargs)


class Tag(models.Model):
    incentiveID = models.ForeignKey(Incentive,related_name="tags")
    tagID= models.IntegerField()
    tagName = models.CharField(max_length=100, blank=True, default='')

    class Meta:
        unique_together = ('incentiveID', 'tagID')

    def save(self, *args, **kwargs):
        super(Tag, self).save(*args, **kwargs)

    def __unicode__(self):
         return '%d: %s' % (self.tagID, self.tagName)

I am sending in this information as JSON

{
    "schemeName": "SendEmails", 
    "schemeID": 1234, 
    "text": "HelloWorld", 
    "typeID": 345, 
    "typeName": "Emails", 
    "status": true, 
    "ordinal": 0, 
    "tags": [{"tagID":123,"tagName":"dor"}], 
    "modeID": 0, 
    "groupIncentive": false, 
    "condition": "SendEmails"
}

And the result I am getting back from the server is

{
    "schemeName": "SendEmails", 
    "schemeID": 1234, 
    "text": "HelloWorld", 
    "typeID": 345, 
    "typeName": "Emails", 
    "status": true, 
    "ordinal": 0, 
    "tags": [], 
    "modeID": 0, 
    "groupIncentive": false, 
    "condition": "SendEmails"
}

How can I make it save the tags as a list?

Upvotes: 0

Views: 791

Answers (1)

Kevin Brown-Silva
Kevin Brown-Silva

Reputation: 41719

Django REST Framework is ignoring the tags that are being sent in being the tags field on the IncentiveSerializer is set to read_only=True, which means that tags cannot be added, they are only able to be read. Because of this, all of the tags are being ignored and nothing is hitting the database.

You can fix this by setting read_only=False instead, but this will require you to override create and update on the serializer, and DRF 3 does not handle nested serializers by default. The Django REST Framework documentation has some useful information for implementing these methods in a generic way, but it will most likely be specific to the serializer.

class IncentiveSerializer(serializers.ModelSerializer):
    tags=TagSerializer(many=True,  read_only=False)

    class Meta:
        model = Incentive
        fields = ('schemeName', 'schemeID','text','typeID','typeName','status','ordinal','tags','modeID',
        'groupIncentive','condition')

    def create(self, validated_data):
        tags_data = validated_data.pop("tags", [])

        # Ignores tags without a tagId
        tags_ids = [tag["tagId"] for tag in tags_data if "tagId" in tag]

        incentive = super(IncentiveSerializer, self).create(validated_data)

        if tags_ids:
            tags = Tag.objects.filter(tagId__in=tags_ids)
            incentive.tags.add(*tags)

        return incentive

This should allow you to add the tags when creating the Incentive, but it requires that the tag already exists and can be found by the tagId. You may need to change this to meet what you are looking for, as the creation and updating of nested objects is very situation dependent.

Upvotes: 1

Related Questions