Dynamic nested serializers: empty validated_data

旧巷老猫 提交于 2019-12-11 15:17:15

问题


Hello everyone !

So to start here is the behavior on one of the endpoint, I am working on:

# GET Request
{
  "id": 1,
  "name": "test",
  "created_date": "date",
  "completed_date": "date",
  "template": { "name" : "test" }, => nested serializers with only the field "name"
  "status": 1,
  "results": [ { __all__ }, ... ], => nested serializers with all the fields
  "groups": [ { "name" }, ... ], => nested serializers with only the field "name"
}

# POST Request
{ 
  "name": "test",
  "template": {"name":"test"}, => nested serializers with only the field "name"
  "groups": [ {"name":"test"} ], => nested serializers with only the field "name"
}

As you can see, the POST and GET request have some of the field as read_only (status, results, events) and nested fields only require the "name" field not all of them.

Here is the Serializers for this endpoint:

class CampaignsSerializer(serializers.ModelSerializer):
    template = TemplatesSerializer(fields=('name'))
    results = ResultsSerializer(many=True, read_only=True)
    groups = GroupsSerializer(many=True, fields=('name'))

    class Meta:
        model = Campaigns
        fields = ('id', 'user_id', 'name', 'created_date', 'completed_date', 'template', 'status', 'results', 'groups', )
        read_only_fields = ('status', 'results', )

    def create(self, validated_data):
        user = None
        request = self.context.get("request")
        if request and hasattr(request, "user"):
            user = request.user

        template = Templates.objects.filter(name=validated_data.pop('template')).first()
        groups = validated_data.pop('groups')
        campaign = Campaigns.objects.create(user_id=user.id, 
                                            template=template.id,
                                            **validated_data)

        for group in groups:
            obj = Groups.objects.filter(**group)
            campaign.groups.add(obj)

        return campaign

class TemplatesSerializer(serializers.ModelSerializer):
    class Meta:
        model = Templates
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        fields = kwargs.pop('fields', None)
        super(TemplatesSerializer, self).__init__(*args, **kwargs)
        if fields is not None:
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

Same thing for `GroupsSerializer`

So with all this, the following line gives me 0 result template = Templates.objects.filter(name=validated_data.pop('template')).first() A template does exists. If I replace validated_data.pop('template') with a hardcoded name it does return an object. But as of right now, it returns None. Because, validated_data.pop('template') is empty... I am not sure why, But I think it's related to the fact that I am dynamically modifying fields. I didn't want to create 2 different serializers (one for post requests and one for get requests). Putting some fields as read_only, and dynamically modifying fields was the good choice here ? What do you think ?

Templates and Groups are the serializers that are causing trouble here. I didn't put the serializer as ReadOnly. I don't see why it's not getting validated... Any insight on this ?

I think this issue is related to this one too: Django Rest Framework : Nested Serializer Dynamic Model Fields

PROGRESS: As far as I debugged, this function returns an empty list... Which is why it's never getting validated... So therefore not at the end list...

@cached_property
    def _writable_fields(self):
        return [
            field for field in self.fields.values() if not field.read_only
        ]

Thanks again !

Regards,

来源:https://stackoverflow.com/questions/55759817/dynamic-nested-serializers-empty-validated-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!