-
-
Notifications
You must be signed in to change notification settings - Fork 957
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
api: use custom json renderer for speed
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
- Loading branch information
Showing
4 changed files
with
123 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import contextlib | ||
from datetime import timedelta | ||
from decimal import Decimal | ||
from typing import Any | ||
|
||
import orjson | ||
from django.db.models.query import QuerySet | ||
from django.utils.encoding import force_str | ||
from django.utils.functional import Promise | ||
from rest_framework.compat import coreapi | ||
from rest_framework.renderers import JSONRenderer as BaseJSONRenderer | ||
|
||
|
||
def default(obj: Any) -> Any: | ||
""" | ||
Render object to JSON. | ||
Adaptation of https://github.com/encode/django-rest-framework/blob/master/rest_framework/utils/encoders.py | ||
but without the overrides for types natively supported by orjson | ||
""" | ||
if isinstance(obj, Promise): | ||
return force_str(obj) | ||
elif isinstance(obj, timedelta): | ||
return str(obj.total_seconds()) | ||
elif isinstance(obj, Decimal): | ||
return float(obj) | ||
elif isinstance(obj, QuerySet): | ||
return tuple(obj) | ||
elif hasattr(obj, "tolist"): | ||
return obj.tolist() | ||
elif (coreapi is not None) and isinstance(obj, coreapi.Document | coreapi.Error): | ||
raise RuntimeError( | ||
"Cannot return a coreapi object from a JSON view. " | ||
"You should be using a schema renderer instead for this view." | ||
) | ||
elif hasattr(obj, "__getitem__"): | ||
cls = list if isinstance(obj, list | tuple) else dict | ||
with contextlib.suppress(Exception): | ||
return cls(obj) | ||
elif hasattr(obj, "__iter__"): | ||
return tuple(item for item in obj) | ||
return obj | ||
|
||
|
||
class JSONRenderer(BaseJSONRenderer): | ||
""" | ||
Renderer which serializes to JSON, using orjson. | ||
""" | ||
|
||
def render(self, data, accepted_media_type=None, renderer_context=None): | ||
""" | ||
Render `data` into JSON, returning a bytestring. | ||
""" | ||
if data is None: | ||
return b"" | ||
|
||
renderer_context = renderer_context or {} | ||
indent = self.get_indent(accepted_media_type, renderer_context) | ||
options = orjson.OPT_NON_STR_KEYS | orjson.OPT_UTC_Z | ||
if indent is not None: | ||
# No other indentation is supported | ||
options |= orjson.OPT_INDENT_2 | ||
|
||
return orjson.dumps(data, default=default, option=options) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters