context in nested serializers django rest framework context in nested serializers django rest framework python-3.x python-3.x

context in nested serializers django rest framework


Ok i found a working solution. I replaced the ChildSerializer assignment in the Parent class with a SerializerMethodField which adds the context. This is then passed to the get_fields method in my CustomModelSerializer:

class ChildSerializer(CustomModelSerializer):    class Meta:        fields = ('c_name', )        model = Childclass ParentSerializer(CustomModelSerializer):    child = serializers.SerializerMethodField('get_child_serializer')    class Meta:        model = Parent        fields = ('p_name', 'child')    def get_child_serializer(self, obj):        serializer_context = {'request': self.context.get('request') }        children = Child.objects.all().filter(parent=obj)        serializer = ChildSerializer(children, many=True, context=serializer_context)        return serializer.data

and in my CustomModelSerializer:

class CustomModelSerializer(rest_serializer_classes.HyperlinkedModelSerializer):    def __init__(self, *args, **kwargs):        """            Make sure a user is coupled to the serializer (needed for permissions)        """        super().__init__(*args, **kwargs)        if not self.context:            self._context = getattr(self.Meta, 'context', {})        try:            self.user = self.context['request'].user        except KeyError:            self.user = None    def get_fields(self):        ret = OrderedDict()        if not self.user:            print("No user associated with object")            return ret        fields = super().get_fields()        # Bypass permission if superuser        if self.user.is_superuser:            return fields        for f in fields:            if has_right(self.user, self.Meta.model.__name__.lower(), f, "read"):                ret[f] = fields[f]        return ret

This seems to work fine, and fields of the child are discarded in the serializer when i either revoke read-rights on Child.c_name or on Parent.child


If you can not change the nature of you child serializer, as in @Kirill Cherepanov and @Robin van Leeuwen answers, a light but not full-integrated solution would be to manually pass the context in __init__() function :

class ChildSerializer(CustomModelSerializer):    class Meta:        fields = ('c_name', )        model = Childclass ParentSerializer(CustomModelSerializer):    child = ChildSerializer(many=True, read_only=True)    class Meta:        model = Parent        fields = ('p_name', 'child')    def __init__(self, *args, **kwargs):        super().__init__(*args, **kwargs)        # We pass the "upper serializer" context to the "nested one"        self.fields['child'].context.update(self.context)


You can use serialziers.ListField instead. ListField automatically passes context to it's child. So, here's your code

class ChildSerializer(ModelSerializer):    class Meta:        fields = ('c_name', )        model = Childclass ParentSerializer(ModelSerializer):    child = serializers.ListField(read_only=True, child=ChildSerializer())    class Meta:        model = Parent        fields = ('p_name', 'child')