[Django]-Serializers.validated_data fields got changed with source value in DRF

2👍

Solution 1:

The fields in validated data is renamed with the source attribute. You can use the renamed attribute in create method of serializer.

For nested serializers, seems the validated data contains OrderedDict. You can convert it to regular Dict, and can get the rule id.

class ProgramSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)
    description = serializers.CharField(style={'base_template': 'textarea.html'})
    rules = PrioritySerializer(source='priority_set', many=True)

    def create(self, validated_data):
        rules_data = validated_data.pop('priority_set')
        program_obj = Program.objects.create(**validated_data)

        priority = 0
        for rule in rules_data:
            rule_obj = Rule.objects.get(pk=dict(rule)["rule"]["id"])
            priority += 1
            Priority.objects.create(program=program_obj, rule=rule_obj, priority=priority)

        return program_obj

Solution 2:

You can make rules with source name priority_set as read_only and can extract it from request data.

class ProgramSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)
    description = serializers.CharField(style={'base_template': 'textarea.html'})
    rules = PrioritySerializer(source='priority_set', many=True, read_only=True)

    def create(self, validated_data):
        rules_data = self.context["request"].data["rules"]
        program_obj = Program.objects.create(**validated_data)

        priority = 0
        for rule in rules_data:
            rule_obj = Rule.objects.get(pk=rule["rule_id"])
            priority += 1
            Priority.objects.create(program=program_obj, rule=rule_obj, priority=priority)

        return program_obj

You will need to pass request context to serializer

serializer = ProgramSerializer(data=request.data, partial=True, context={"request": request})

Solution 3:

Add related_name in program Foreign key in Priority model.

program = models.ForeignKey(Program, related_name="rule", on_delete=models.CASCADE)

Rename rules field in ProgramSerializer to something else e.g. rule, and remove source.

class ProgramSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)
    description = serializers.CharField(style={'base_template': 'textarea.html'})
    rule = PrioritySerializer(many=True)

    def create(self, validated_data):
        rules_data = validated_data.pop('rule')
        program_obj = Program.objects.create(**validated_data)

        priority = 0
        for rule in rules_data:
            rule_obj = Rule.objects.get(pk=dict(rule)["rule"]["id"])
            priority += 1
            Priority.objects.create(program=program_obj, rule=rule_obj, priority=priority)

        return program_obj

Now you will be able to post and retrieve data with rule key. You can rename it something else as appropriate.

Leave a comment