Skip to content

Instantly share code, notes, and snippets.

@czue
Last active December 15, 2023 21:41
Show Gist options
  • Select an option

  • Save czue/90e287c9818ae726f73f5850c1b00f7f to your computer and use it in GitHub Desktop.

Select an option

Save czue/90e287c9818ae726f73f5850c1b00f7f to your computer and use it in GitHub Desktop.
A simple django template tag that lets you automatically render json from a python object
"""
Usage:
{% load json_tags %}
var = myJsObject = {{ template_var|to_json }};
Features:
- Built in support for dates, datetimes, lazy translations.
- Safe escaping of script tags.
- Support for including QuryDict objects.
- Support for custom serialization methods on objects via defining a `to_json()` method.
"""
import datetime
import json
from decimal import Decimal
from django import template
from django.conf import settings
from django.http import QueryDict
from django.utils.encoding import force_str
from django.utils.functional import Promise
from django.utils.safestring import mark_safe
register = template.Library()
ISO_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
def json_handler(obj):
if callable(getattr(obj, 'to_json', None)):
return obj.to_json()
elif isinstance(obj, datetime.datetime):
return obj.strftime(ISO_DATETIME_FORMAT)
elif isinstance(obj, datetime.date):
return obj.isoformat()
elif isinstance(obj, datetime.time):
return obj.strftime('%H:%M:%S')
elif isinstance(obj, Decimal):
return float(obj) # warning, potential loss of precision
elif isinstance(obj, Promise):
return force_str(obj) # to support ugettext_lazy
else:
return json.JSONEncoder().default(obj)
@register.filter
def to_json(obj):
def escape_script_tags(unsafe_str):
# seriously: http://stackoverflow.com/a/1068548/8207
return unsafe_str.replace('</script>', '<" + "/script>')
# json.dumps does not properly convert QueryDict array parameter to json
if isinstance(obj, QueryDict):
obj = dict(obj)
# apply formatting in debug mode for ease of development
indent = None
if settings.DEBUG:
indent = 2
return mark_safe(escape_script_tags(json.dumps(obj, default=json_handler, indent=indent)))
@aruseni
Copy link
Copy Markdown

aruseni commented Jul 16, 2018

Hi czue! The tag for loading tags is load. So you should change import to load in the description.

@czue
Copy link
Copy Markdown
Author

czue commented Jan 22, 2019

thanks! sorry that was a silly mistake.

@mark0978
Copy link
Copy Markdown

You can make it a tiny bit better with this:

    indent = None
    if settings.DEBUG:
        indent = 2
    return mark_safe(escape_script_tags(json.dumps(obj, default=json_handler, indent=indent)))

So that the JSON is minimal when in production and more readable when in DEBUG mode.

@czue
Copy link
Copy Markdown
Author

czue commented Sep 1, 2019

Thanks for the suggestion @mark0978 ! Updated.

@SOesterreicher
Copy link
Copy Markdown

Hello Cory Zue,
under which license do you offer this code snippet? Any easy permissive license?
Thanks in advance
Siegfried

@czue
Copy link
Copy Markdown
Author

czue commented Nov 14, 2019

sure, yeah do whatever you want with it! I don't know if a github comment is binding but feel free to consider it MIT

@SOesterreicher
Copy link
Copy Markdown

Thank you very much.
Siegfried

@Veilkrand
Copy link
Copy Markdown

you need to import settings in order to use settings.debug in line 58.
from django.conf import settings

@czue
Copy link
Copy Markdown
Author

czue commented Jan 14, 2021

oops, thanks! fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment