"""Fields useful for edX API implementations.""" from rest_framework.serializers import Field, URLField class ExpandableField(Field): """Field that can dynamically use a more detailed serializer based on a user-provided "expand" parameter. Kwargs: collapsed_serializer (Serializer): the serializer to use for a non-expanded representation. expanded_serializer (Serializer): the serializer to use for an expanded representation. """ def __init__(self, **kwargs): """Sets up the ExpandableField with the collapsed and expanded versions of the serializer.""" assert 'collapsed_serializer' in kwargs and 'expanded_serializer' in kwargs self.collapsed = kwargs.pop('collapsed_serializer') self.expanded = kwargs.pop('expanded_serializer') super(ExpandableField, self).__init__(**kwargs) def to_representation(self, obj): """ Return a representation of the field that is either expanded or collapsed. """ should_expand = self.field_name in self.context.get("expand", []) field = self.expanded if should_expand else self.collapsed # Avoid double-binding the field, otherwise we'll get # an error about the source kwarg being redundant. if field.source is None: field.bind(self.field_name, self) if should_expand: self.expanded.context["expand"] = set(field.context.get("expand", [])) return field.to_representation(obj) class AbsoluteURLField(URLField): """ Field that serializes values to absolute URLs based on the current request. If the value to be serialized is already a URL, that value will returned. """ def to_representation(self, value): request = self.context.get('request', None) assert request is not None, ( "`%s` requires the request in the serializer context. " "Add `context={'request': request}` when instantiating the serializer." % self.__class__.__name__ ) if value.startswith(('http:', 'https:')): return value return request.build_absolute_uri(value)