def process(self, obj, parent=None, parent_key=None, depth=0):
        """Recursively process the data for sideloading.

        Converts the nested representation into a sideloaded representation.
        """
        if isinstance(obj, list):
            for key, o in enumerate(obj):
                # traverse into lists of objects
                self.process(o, parent=obj, parent_key=key, depth=depth)
        elif isinstance(obj, dict):
            dynamic = self.is_dynamic(obj)
            returned = isinstance(obj, ReturnDict)
            if dynamic or returned:
                # recursively check all fields
                for key, o in six.iteritems(obj):
                    if isinstance(o, list) or isinstance(o, dict):
                        # lists or dicts indicate a relation
                        self.process(
                            o,
                            parent=obj,
                            parent_key=key,
                            depth=depth +
                            1
                        )

                if not dynamic or getattr(obj, 'embed', False):
                    return

                serializer = obj.serializer
                name = serializer.get_plural_name()
                instance = getattr(obj, 'instance', serializer.instance)
                instance_pk = instance.pk if instance else None
                pk = getattr(obj, 'pk_value', instance_pk) or instance_pk

                # For polymorphic relations, `pk` can be a dict, so use the
                # string representation (dict isn't hashable).
                pk_key = repr(pk)

                # sideloading
                seen = True
                # if this object has not yet been seen
                if pk_key not in self.seen[name]:
                    seen = False
                    self.seen[name].add(pk_key)

                # prevent sideloading the primary objects
                if depth == 0:
                    return

                # TODO: spec out the exact behavior for secondary instances of
                # the primary resource

                # if the primary resource is embedded, add it to a prefixed key
                if name == self.plural_name:
                    name = '%s%s' % (
                        settings.ADDITIONAL_PRIMARY_RESOURCE_PREFIX,
                        name
                    )

                if not seen:
                    # allocate a top-level key in the data for this resource
                    # type
                    if name not in self.data:
                        self.data[name] = []

                    # move the object into a new top-level bucket
                    # and mark it as seen
                    self.data[name].append(obj)
                else:
                    # obj sideloaded, but maybe with other fields
                    for o in self.data.get(name, []):
                        if o.instance.pk == pk:
                            o.update(obj)
                            break

                # replace the object with a reference
                if parent is not None and parent_key is not None:
                    parent[parent_key] = pk
Recursively process the data for sideloading.

        Converts the nested representation into a sideloaded representation.