Skip to content

renderers#

MsgspecJSONRenderer#

Bases: BaseRenderer

JSON Renderer utilizing msgspec

Msgspec is faster, uses less memory and natively supports more types than the standard json library. See: https://jcristharif.com/msgspec/

Source code in src/apps/common/renderers.py
class MsgspecJSONRenderer(renderers.BaseRenderer):
    """JSON Renderer utilizing msgspec

    Msgspec is faster, uses less memory and natively supports
    more types than the standard json library.
    See: https://jcristharif.com/msgspec/
    """

    media_type = "application/json"
    format = "json"
    charset = None

    def encoder_default(self, obj: Any) -> Any:
        """Any types not recognized by msgspec should be added here.

        For examples, see rest_framework.utils.encoders.JSONEncoder.
        """
        if isinstance(obj, Promise):
            return force_str(obj)
        elif isinstance(obj, QuerySet):
            return tuple(obj)
        elif isinstance(obj, str):  # ErrorDetail is a subclass of str
            return str(obj)
        raise NotImplementedError(
            f"Object of type {obj.__class__.__name__} is not JSON serializable"
        )

    def get_indent(self, accepted_media_type, renderer_context):
        if accepted_media_type:
            _base_media_type, params = parse_header_parameters(accepted_media_type)
            with contextlib.suppress(KeyError, ValueError, TypeError):
                if params.get("indent"):
                    return max(min(int(params["indent"]), 8), 0)
        # The indent may be provided in the context, e.g. in BrowsableAPIRenderer
        return renderer_context.get("indent")

    def render(self, data, media_type=None, renderer_context=None):
        if data is None:
            return b""

        request = renderer_context["request"]
        if t_format := request.META.get("HTTP_TIME_FORMAT"):
            # Change the format of all DateTime fields in the response data
            data = self.adjust_datetime_format(data, t_format)

        buf = msgspec.json.encode(data, enc_hook=self.encoder_default)
        if indent := self.get_indent(media_type, renderer_context):
            buf = msgspec.json.format(buf, indent=indent)
        return buf

    def adjust_datetime_format(self, data, time_format):
        datetime_pattern = r"^\d{4}-\d{2}"
        if isinstance(data, list):
            return [self.adjust_datetime_format(item, time_format) for item in data]
        elif isinstance(data, dict):
            return {
                key: self.adjust_datetime_format(value, time_format) for key, value in data.items()
            }
        elif isinstance(data, str):
            if re.match(datetime_pattern, data) is not None:
                try:
                    datetime_obj = parse_datetime(data)
                    current_timezone = timezone.get_current_timezone()
                    if timezone.is_naive(datetime_obj):
                        datetime_obj = timezone.make_aware(datetime_obj, current_timezone)
                    utc_datetime = datetime_obj.astimezone(tz.utc)
                    return utc_datetime.strftime(time_format)
                except ValueError as e:
                    logger.error(e)
                    return data
            else:
                return data
        else:
            return data

encoder_default(obj) #

Any types not recognized by msgspec should be added here.

For examples, see rest_framework.utils.encoders.JSONEncoder.

Source code in src/apps/common/renderers.py
def encoder_default(self, obj: Any) -> Any:
    """Any types not recognized by msgspec should be added here.

    For examples, see rest_framework.utils.encoders.JSONEncoder.
    """
    if isinstance(obj, Promise):
        return force_str(obj)
    elif isinstance(obj, QuerySet):
        return tuple(obj)
    elif isinstance(obj, str):  # ErrorDetail is a subclass of str
        return str(obj)
    raise NotImplementedError(
        f"Object of type {obj.__class__.__name__} is not JSON serializable"
    )

NoHTMLFormBrowsableAPIRenderer#

Bases: BrowsableAPIRenderer

Source code in src/apps/common/renderers.py
class NoHTMLFormBrowsableAPIRenderer(renderers.BrowsableAPIRenderer):
    def get_rendered_html_form(self, *args, **kwargs):
        """
        The Browsable API HTML forms do not support lists or dictionaries which
        makes them unusable for e.g. creating a dataset so we hide the form.
        """
        return None

get_rendered_html_form(*args, **kwargs) #

The Browsable API HTML forms do not support lists or dictionaries which makes them unusable for e.g. creating a dataset so we hide the form.

Source code in src/apps/common/renderers.py
def get_rendered_html_form(self, *args, **kwargs):
    """
    The Browsable API HTML forms do not support lists or dictionaries which
    makes them unusable for e.g. creating a dataset so we hide the form.
    """
    return None