fields.py 2.11 KB
Newer Older
1
"""Fields useful for edX API implementations."""
2
from rest_framework.serializers import Field, URLField
3 4 5


class ExpandableField(Field):
6 7 8 9 10 11
    """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.
    """
12

13 14 15 16 17 18 19
    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)

20 21 22 23 24 25
    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
26

27 28 29 30
        # 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)
31

32
            if should_expand:
33
                self.expanded.context["expand"] = set(field.context.get("expand", []))
34

35
        return field.to_representation(obj)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56


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)